我最早接觸MSP430時候,看到書的第一頁就是一張水果電池的圖片,一直以來想做一個低功耗的可以水果電池供電的系統,畢業之后的下半年選擇MSP430F413單片機來畫了一個低功耗的板子,一直沒有調試成功,液晶顯示太暗幾乎看不到,最近又拿出來調試,更換偏壓電阻,最終更換液晶后才可以正常顯示,先看下最終效果:
最終效果
電路圖:
調試過程
最初調試時,先准備好蘋果一個,電池正負極(銅鋅),程序是顯示一個數字,效果如下:
突發奇想,用自來水試了一下,效果也是杠杠的(程序中間修改過,這是顯示較多的液晶段):
時鍾調試效果(這里電池沒有接入電路,調試時所用,當時沒有拿下來,用跳線帽接到水果供電的電路上):
剛剛調試時,萬用表測試水果電池電壓接近0.9V,短路電流25-30uA,接上電路僅顯示數字7的時候,電流12uA,4節水果電池電壓從3.4降到2.6V;水(普通自來水,每個地方水中含有離子數量不一樣,獲得電壓電流都有區別)每節電池0.8V,短路電流接近40uA。
程序換為時鍾時,水果電池3.4V降到2.2V,大約維1個多小時,液晶完全沒有顯示,電極片換個位置重新插一下,時鍾可以繼續運行,測試電壓和新做水果電池一樣,蘋果都要變干的時候,電壓低一些,液晶明顯變暗。
后來,電路中提供液晶偏壓電壓的電阻有330K改為1M后,系統電流降到大約10uA,水果電池大約可以維持3-4小時,用水做的電池可以維持24小時以上
功耗分析
這個低功耗的電路還有優化空間,單片機的不用的引腳可以再做優化,現有線路中有一般的液晶段引腳沒有使用,卻也提供的驅動波形,這里相對現有系統應當是浪費電流最大的一部分;另外一個優化空間是4個按鍵的上拉電阻太小,10K,3V的時候,按鍵按下瞬間,電流可以達到300uA,用水果電池的時候,按鍵功能不能使用,現在調試的時候,都是先拿CR2302供電,調節好時間后,再用水果(水)電池供電。
進一步優化功耗后,電流應當可以降到5uA以下。
程序
按鍵程序繼續使用之前程序庫中的按鍵程序;
RTC計時使用TI的RTC軟件庫
段碼液晶的程序由程序庫中的數碼管程序移植而來:
#include <msp430x41x.h>
#include "segment_lcd_btl006.h"
/*宏定義,數碼管a-h各段對應的比特,更換硬件只用改動以下8行*/
#define a 0x01 // AAAA
#define b 0x02 // F B
#define c 0x04 // F B
#define d 0x80 // GGGG
#define e 0x40 // E C
#define f 0x10 // E C
#define g 0x20 // DDDD HH
#define h 0x08 //小數點
/*用宏定義自動生成段碼表,很好的寫法,值得學習*/
/*更換硬件無需重寫段碼表*/
const char tab[] = {
a + b + c + d + e + f, // Displays "0"
b + c, // Displays "1"
a + b + d + e + g, // Displays "2"
a + b + c + d + g, // Displays "3"
b + c + f + g, // Displays "4"
a + c + d + f +g, // Displays "5"
a + c + d + e + f + g, // Displays "6"
a + b + c, // Displays "7"
a + b + c + d + e + f + g, // Displays "8"
a + b + c + d + f + g, // Displays "9"
a + b + c + e + f + g, // Displays "A"
c + d + e + f + g, // Displays "B"
a + d + e + f, // Displays "C"
b + c + d + e + g, // Displays "D"
a + d + e + f + g, // Displays "E"
a + e + f + g, // Displays "F"
a + c + d + e + f, // Displays "G"
b + c + e + f + g, // Displays "H"
e + f, // Displays "I"
b + c + d + e, // Displays "J"
b + d + e + f + g, // Displays "K"
d + e + f, // Displays "L"
a + c + e + g, // Displays "M"
a + b + c + e + f, // Displays "N"
c + e + g, // Displays "n"
c + d + e + g, // Displays "o"
a + b + c + d + e + f, // Displays "O"
a + b + e + f + g, // Displays "P"
a + b + c + f + g, // Displays "Q"
e + g, // Displays "r"
a + c + d + f +g, // Displays "S"
d + e + f + g, // Displays "t"
a + e + f , // Displays "T"
b + c + d + e + f, // Displays "U"
c + d + e, // Displays "v"
b + d + f + g, // Displays "W"
b + c + d + f + g, // Displays "Y"
a + b + d + e + g, // Displays "Z"
g, // Displays "-"
h, // Displays "."
0 // Displays " "
};
#undef a
#undef b
#undef c
#undef d
#undef e
#undef f
#undef g
void lcd_init()
{
// Initialize LCD
LCDCTL = LCDP1+LCDP0+LCD4MUX+LCDON; // 4-Mux LCD, segments S0-S23
BTCTL = BTFRFQ1; // Set freqLCD = ACLK/128
P5SEL = 0xFC; // Set Rxx and COM pins for LCD
// Clear LCD memory to clear display
for (int i=0; i<12; i++)
{
LCDMEM[i] = 0x00;
}
}
void lcd_clear()
{
for (int i=0; i<12; i++)
{
LCDMEM[i] = 0x00;
}
}
//不影響小數點或者冒號
void lcd_display_char(char ch,char addr)
{
addr = addr*2+2;
LCDMEM[addr] = ((tab[ch]&0x0f)<<4)|(LCDMEM[addr]&0x80);
LCDMEM[addr+1] = (tab[ch]&0xf0);//|(LCDMEM[addr+1]&0x80)
}
計時程序,每隔1s中斷運行一次,計時則秒增1,設置則顯示對應設置界面:
#include <msp430x41x.h>
#include "RTC_Calendar.h"
#include "RTC_TA.h"
#include "segment_lcd_btl006.h"
#include "time.h"
char state = 0; //1-6:年月日 時分秒
void time_init()
{
lcd_init();
setDate(2015,9,13);
setTime( 0, 0, 0, 1); // initialize time to 12:00:00 AM
TACCR0 = 32768-1;
TACTL = TASSEL_1+MC_1; // ACLK, upmode
TACCTL0 |= CCIE; // enable TA0CCRO interrupt
}
//兩位時間顯示,格式十六進制高地位 地址0低位,1高位
void time_display(char time,char addr)
{
addr = addr*2;
lcd_display_char(time>>4,addr+1);
lcd_display_char((time&0x0f),addr);
}
//4位時間顯示,year,格式十六進制各個位
void year_display(int year)
{
lcd_display_char(year>>12,3);
lcd_display_char((year>>8)&0x0f,2);
lcd_display_char((year>>4)&0x0f,1);
lcd_display_char((year)&0x0f,0);
}
//計時標志,冒號閃爍
void tick()
{
LCDMEM[1]&=~0X80;
LCDMEM[2]^=0x80;
time_display(get24Hour(),1);
time_display(TI_minute,0);
}
void setting()
{
LCDMEM[1]=0X80;
switch(state)
{
case 1:
year_display(TI_year);
break;
case 2:
time_display(TI_month==9?TI_month+7:TI_month+1,1);
break;
case 3:
time_display(TI_day,0);
break;
case 4:
time_display(get24Hour(),1);
LCDMEM[2]|=0x80;
break;
case 5:
time_display(TI_minute,0);
LCDMEM[2]|=0x80;
break;
case 6:
time_display(TI_second,0);
LCDMEM[2]|=0x80;
break;
default:
state = 0;
break;
}
}
// Timer A0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
incrementSeconds();
if(state == 0)
{
tick();
}
else
{
setting();
}
__bic_SR_register_on_exit(LPM3_bits);
}
主函數,根據按鍵更改操作狀態,並且設置時間值:
#include <msp430x41x.h>
#include "RTC_Calendar.h"
#include "RTC_TA.h"
#include "segment_lcd_btl006.h"
#include "time.h"
#include "key.h"
int main( void )
{
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
FLL_CTL0 |= XCAP14PF; // Configure load caps
time_init();
KeyInit();
__bis_SR_register(GIE);
while(1)
{
__bis_SR_register(LPM3_bits); // enter LPM3, clock will be updated
char key = ReadKey();
if(key=='0'&&state==1)
{
setDate(2015,TI_month>9?TI_month-5:TI_month+1,(TI_day>>4)*10+(TI_day&0x0f));
}
if(key=='1')
{
if(++state == 7)
{
state = 0;
}
}
if(key=='2')
{
switch(state)
{
case 1:
incrementYears();
break;
case 2:
incrementMonths();
break;
case 3:
incrementDays();
break;
case 4:
incrementHours();
break;
case 5:
incrementMinutes();
break;
case 6:
incrementSeconds();
break;
default:
state = 0;
break;
}
}
if(state!=0)
{
lcd_clear();
setting();
}
else
{
tick();
}
}
return 0;
}
最新運行效果
上午剛剛拍的,昨天(2015-10-02)晚上,發覺液晶有些暗,水里面加了一些鹽,顯示效果更好一些,運行時間應該也會更久: