基于MSP430G2231分辨率为0.1℃普通IO口驱动LCD的温度计
wenyangzeng 2012/04/30
为了降低成本,采用MSP430G2231单片机普通IO口驱动段码型LCD,本设计使用了2个中断源,在CCR0中断中顺序产生1/2Bias的COM0-COM3位码扫描信号,并通过USI-SPI功能控制1片74HC595产生8位段码信号,驱动了4位8段LCD显示屏。在CCR1中断中清零LCD显示数据,并产生ADC允许转换信号。温度传感器则利用MSP430G2231内部温度传感器,主程序检测到ADC允许转换信号后进行一次ADC转换,通过采用过采样技术,在采样10次温度值后,进行运算,得到精度达0.1℃的温度测量结果。
设计直接利用LanuchPad 实验板扩展槽,连接1片PCB板,板上焊接74HC595和LCD和COM分压电阻等。编译环境使用IAR-MSP430 for 5.40限制版,该版本将仿真窗口中变量、寄存器观察窗的显示值都屏蔽掉了,有点太吝舍了,给调试过程带来不少麻烦。
运行结果见图1。
图1 运行结果
图2 原理图
附:代码
#include <msp430g2231.h>
#define setbit(var,bit) ((var)|=(1<<(bit)))
#define clrbit(var,bit) ((var)&=~(1<<(bit)))
unsigned char frame[4]; /* LCD frame buffer */
unsigned char digit[4]; /* Digit frame buffer */
// LCD segment definitions (SoftBaugh SBLCDA4)
#define SEG_D 0x01 // AAAA
#define SEG_C 0x04 // F B
#define SEG_B 0x40 // F B
#define SEG_A 0x80 // GGGG
#define SEG_H 0x02 // E C
#define SEG_E 0x08 // E C
#define SEG_G 0x10 // DDDD
#define SEG_F 0x20
#define DIG_c (SEG_E + SEG_G+ SEG_D) // Displays 'c'
unsigned char const number[17] = {
(SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F), // "0"
(SEG_B | SEG_C), // "1"
(SEG_A + SEG_B + SEG_D + SEG_E + SEG_G), // "2"
(SEG_A + SEG_B + SEG_C + SEG_D + SEG_G), // "3"
(SEG_B + SEG_C + SEG_F + SEG_G), // "4"
(SEG_A + SEG_C + SEG_D + SEG_F + SEG_G), // "5"
(SEG_A + SEG_C + SEG_D + SEG_E + SEG_F + SEG_G), // "6"
(SEG_A + SEG_B + SEG_C), // "7"
(SEG_A + SEG_B + SEG_C + SEG_D + SEG_E + SEG_F + SEG_G), // "8"
(SEG_A + SEG_B + SEG_C + SEG_D + SEG_F + SEG_G), // "9"
(SEG_A + SEG_B + SEG_C + SEG_E + SEG_F + SEG_G), // "A"
(SEG_C + SEG_D + SEG_E + SEG_F + SEG_G), // "B"
(SEG_A + SEG_D + SEG_E + SEG_F), // "C"
(SEG_B + SEG_C + SEG_D + SEG_E + SEG_G), // "D"
(SEG_A + SEG_D + SEG_E + SEG_F +SEG_G), // "E"
(SEG_A + SEG_E + SEG_F + SEG_G), // "F"
0x00 // Blank
};
long temp;
long DegC;
long IntDegC;
unsigned char Seg_Old,dispbuf[4];
unsigned char var=0,lcdcr=0,ADC_EN=0,t=0;
void display(unsigned int Number,unsigned char D_OR_H);
void main(void)
{unsigned char j=0;
WDTCTL = WDTPW + WDTHOLD;
P1OUT = 0X00;
P1DIR = 0xFF;
USICTL0 |= USIPE7 + USIPE6 + USIPE5 + USIMST + USIOE;
USICTL1 |= USICKPH;
USICKCTL = USIDIV_1 + USISSEL_2;
USICTL0 &= ~USISWRST;
USICNT = 8;
CCTL0 = OUTMOD_3 + CCIE;
CCTL1 = OUTMOD_3 + CCIE;
TACCR0 = 200;
TACTL = TASSEL_2 + MC_2 ;
ADC10CTL1 = INCH_10 ;//+ ADC10DIV_3;
ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON ;
_EINT();
temp=0;
for(;;)
{
if(ADC_EN==1)
{ ADC_EN=0;
ADC10CTL0 |= ENC + ADC10SC;
while (!(ADC10IFG & ADC10CTL0));
temp += ADC10MEM;
j++;
if(j==10)
{
IntDegC = ((temp – 673) * 423) / 1024;
display(IntDegC,1);
j=0;temp=0;
}
}
}
}
//——————————————–
// Timer A0 interrupt service routine
//——————————————-
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A0 (void)
{ unsigned char i;
if(var==0)
{
var++;
if(lcdcr==0)
Seg_Old=frame[0];
else
if(lcdcr==1)
Seg_Old=frame[1];
else
if(lcdcr==2)
Seg_Old=frame[2];
else
if(lcdcr==3)
Seg_Old=frame[3];
while (!(USIIFG & USICTL1));
USISRL = Seg_Old;
USICNT = 8;
for(i=4;i>0;i–);
P1OUT |= BIT4;
P1OUT &=~BIT4;
P1DIR &=~0X0F;
clrbit(P1OUT,lcdcr);
setbit(P1DIR,lcdcr);
}
else
{
var=0;
while (!(USIIFG & USICTL1));
Seg_Old=~Seg_Old;;
USISRL = Seg_Old;
USICNT = 8;
for(i=4;i>0;i–);
P1OUT |= BIT4;
P1OUT &=~BIT4;
P1DIR &=~0X0F;
setbit(P1OUT,lcdcr);
setbit(P1DIR,lcdcr);
lcdcr++;
if (lcdcr>3) lcdcr =0;
}
CCR0 += 2300;
}
//—————————————————
// Timer_A2 Interrupt Vector (TAIV) handler
//————————————————–
#pragma vector=TIMERA1_VECTOR
__interrupt void Timer_A1(void)
{
switch( TAIV )
{unsigned char i;
case 2:
{ t++;
if(t==50)
{ADC_EN=1;
t=0;
}
while (!(USIIFG & USICTL1));
USISRL = 0x00;
USICNT = 8;
for(i=4;i>0;i–);
P1OUT |= BIT4;
P1OUT &=~BIT4;
P1OUT &=~0x0f; //com全为0
P1DIR |=0X0F;
CCR1 += 2300;
break;
}
case 10: break;
}
}
//——————————————————
//显示4位数字函数
//入口参数1:16位数值
//入口参数2:0-16进制/1-十进制
//—————————————————–
void display(unsigned int Number,unsigned char D_OR_H)
{ unsigned char a,b,c,d;
if(D_OR_H==1)
{
a=Number%10000/1000;
b=Number%1000/100;
c=Number%100/10;
d=Number%10;
}
else
{ a=(Number>>12)&0x0f;
b=(Number>>8)&0x0f;
c=(Number>>4)&0x0f;
d=Number&0x0f;
}
dispbuf[0]= DIG_c ;//number[d];
dispbuf[1]= number[c]|SEG_H;
dispbuf[2]= number[b];
dispbuf[3]= number[a];
frame[0]=dispbuf[0]&0x03;
frame[0] |=(dispbuf[1]<<2)&0x0c;
frame[0] |=(dispbuf[2]<<4)&0x30;
frame[0] |=(dispbuf[3]<<6)&0xc0;
frame[1]=(dispbuf[0]>>2)&0x03;
frame[1] |=(dispbuf[1]&0x0c);
frame[1] |=(dispbuf[2]<<2)&0x30;
frame[1] |=(dispbuf[3]<<4)&0xc0;
frame[2] =(dispbuf[0]>>4)&0x03;
frame[2] |=(dispbuf[1]>>2)&0x0c;
frame[2] |=dispbuf[2]&0x30;
frame[2] |=(dispbuf[3]<<2)&0xc0;
frame[3] =(dispbuf[0]>>6)&0x03;
frame[3] |=(dispbuf[1]>>4)&0x0c;
frame[3] |=(dispbuf[2]>>2)&0x30;
frame[3] |=(dispbuf[3]&0xc0);
}
wenyang zeng:
wenyang zeng:
为何图片上传后看不见??
wenyang zeng:
wenyang zeng基于MSP430G2231分辨率为0.1℃普通IO口驱动LCD的温度计
wenyangzeng 2012/04/30为了降低成本,采用MSP430G2231单片机普通IO口驱动段码型LCD,本设计使用了2个中断源,在CCR0中断中顺序产生1/2Bias的COM0-COM3位码扫描信号,并通过USI-SPI功能控制1片74HC595产生8位段码信号,驱动了4位8段LCD显示屏。在CCR1中断中清零LCD显示数据,并产生ADC允许转换信号。温度传感器则利用MSP430G2231内部温度传感器,主程序检测到ADC允许转换信号后进行一次ADC转换,通过采用过采样技术,在采样10次温度值后,进行运算,得到精度达0.1℃的温度测量结果。
设计直接利用LanuchPad 实验板扩展槽,连接1片PCB板,板上焊接74HC595和LCD和COM分压电阻等。编译环境使用IAR-MSP430 for 5.40限制版,该版本将仿真窗口中变量、寄存器观察窗的显示值都屏蔽掉了,有点太吝舍了,给调试过程带来不少麻烦。
图1 运行结果
图2 原理图Fuchong Wang:
回复 wenyang zeng:
应该说是显示分辨率吧,好像内部温度传感器只能0.5左右的理论分辨率吧
功耗多少?
Charles Wu:
回复 Fuchong Wang:
没仔细看代码,看楼主说明里的意思,4个COM的电压都是一样的?全是1/2Vcc?
Charles Wu:
回复 Charles Wu:
另外,楼主用的IAR应该是4K的代码限制版吧。貌似watch,variable这些观察窗口都是可以用的啊,只是默认没有选择打开罢了。
wenyang zeng:
回复 Fuchong Wang:
谢谢楼上的细心指教。是你所说的显示分辨率。
wenyang zeng:
回复 Charles Wu:
4个COM当然都是1/2VCC,定时器中断里对它们进行分时扫描,分别得到VCC-1/2/VCC-0V的电压。
wenyang zeng:
回复 Charles Wu:
watch,variable这些观察窗口都是可以用,但是它们的仿真值显示不出来。
Fuchong Wang:
回复 wenyang zeng:
setbit(P1OUT,lcdcr);
setbit(P1DIR,lcdcr);
看着累吆
这种类型的LCD用MSP430操作,谁试验过到底可以做到最低功耗多少?例如做个最基本的电子时钟。如果考虑到功耗,难道只有用内部集成驱动的?