我正在尝试在MSP430G2553上实现一个温度传感器,用于读取和输出温度读数以及时间戳。基本要求如下:
• t:显示系统的当前时间。使用hhmmss形式向串行终端输出系统的当前时间,其中hh是24小时格式的两位数小时,mm是小时中的两位数分钟,ss是分钟内的两位数秒。
• s:设置系统的当前时间。将系统的当前时间设置为提供的参数。命令及其参数之间没有空格。参数将以 hhmmss 的形式出现,其中 hh 是 24 小时格式的两位数小时,mm 是小时中的两位数分钟,ss 是分钟内的两位数秒。
• o:显示最早的温度读数及其时间戳。向串行终端输出最新的温度读数及其时间戳。输出必须采用 hhmmsss 格式:T,其中 hh 是 24 小时格式的两位数小时,mm 是小时中的两位数分钟,ss 是分钟内的两位数秒,T 是测量的温度。必须从列表中删除显示的条目。如果未执行读数,则必须显示消息"未记录温度"。
• l:显示所有温度读数及其时间戳。向串行终端输出所有温度读数及其时间戳。输出应按时间顺序排列,最早的在前。输出必须采用 hhmmsss 格式:T,其中 hh 是 24 小时格式的两位数小时,mm 是小时中的两位数分钟,ss 是分钟内的两位数秒,T 是测量的温度。必须从列表中删除所有条目。如果未执行读数,则必须显示消息"未记录温度"。 您的系统还必须满足以下要求:
• 您必须每五 (5) 分钟捕获一次新的温度读数,并至少存储 32 个温度读数。如果已达到最大温度读数,请在存储新温度读数之前丢弃最旧的读数。
输入"t"2 次后出错。下次我输入"t"时,它会输出 3 或 4 个垃圾值。当我注释掉"s"大小写或将"s"更改为不同的变量时,我在 switch 语句中的"t"情况运行得很好,但赋值的情况需要输入到 uart 中,情况为"s"。到目前为止,我尝试的包括:更改变量,注释掉第二种情况,更改 S 情况的值以确保垃圾值是由于这种情况而生成的,使用代码某些部分的括号,修改了整个 t 情况的第一部分以提高效率,但仍然出现相同的错误,等。任何建议都会非常有帮助。垃圾值图片
#include "msp430g2553.h"
volatile short unsigned int i=0,j=0,k=0;//This the integer that track the number of cycles
volatile short unsigned int timercount=0;//This the integer that track the number of cycles
volatile unsigned int GT=2600;//variable that sets the global time in seconds of the system
volatile char inputcharacters[16];//Input character storage array
volatile unsigned int tempature[32];//
volatile unsigned int tempaturetime[32];
volatile unsigned int d[6]={0,0,0,0,0,0},test[7];
volatile unsigned int h=0;
volatile unsigned int m=0;
volatile unsigned int ss=0;
int temp=0;
void main(void)
{
WDTCTL = WDTPW + WDTHOLD;//Disabling watchdogtimer
P1DIR |= BIT0;//setting p1 bit 1 to outy
P1OUT &= ~BIT0;//Shutting off the LED
/* UART config for 9600 baud with SMCLK*/
IE2 = 0x00;//interrupts off on UART
UCA0CTL1 = 0x81;//using SMCLK(1Mhz) and software reset enable
UCA0CTL0 = 0x00;//eight data bits, no parity, one stop bit
UCA0MCTL = 0x02;//Setting UCBRSx to 1 to set clock rate to 9600
UCA0BR0 = 0x68;//set clock rate to 9600 from 1Mhz
UCA0BR1 = 0x00;//set clock rate to 9600
UCA0STAT = 0x00;//error check and parity, and frame error check all off
TACTL = 0x1D0;// sets timer a to use the 32.768kh clock with 8 divisor and in up mode
TACCR0 = 0x1001;// setting the timer to count up to 4097 to get a 1hz(1s) oscillation
TACCTL0 &= 0xFFEF;// disable capture compare interrupts
P1SEL|=0X06;// According to slas735j both p1.1(0X02) and p1.2(0X04) need to be set on to receive and send on the UART
P1SEL2|=0X06;
ADC10CTL0 &= ENC;
ADC10CTL0 = SREF_1 | ADC10SHT_3 | REFON | ADC10ON;
ADC10CTL1 = INCH_10 | ADC10DIV_2 | ADC10SSEL_3;
//ADC10CTL0 = 0x3030;
//ADC10CTL1 = 0xA038;
ADC10CTL0 &= 0xFFFC;
/* Enable USCI logic and Enable interrupts */
UCA0CTL1 &= 0xFE;//turning on USCI logic
IE2 = 0x01;// Sets UART to receive interrupt
TACCTL0 = CCIE;// set timerA interupts on done last
__bis_SR_register(LPM3_bits + GIE);//found on TI wiki
}
#pragma vector=USCIAB0RX_VECTOR// This vector name was pulled from the webcources code
__interrupt void uartinput(void)//this form found on TI's wiki
{
inputcharacters[i] = UCA0RXBUF;
UCA0TXBUF = UCA0RXBUF;
if((i>14)||(inputcharacters[i]=='r'))
{if(inputcharacters[i]=='r'){inputcharacters[i]=0;}//to reduce i, the number of inputs so that we dont count the r
for(j=0;j<i;j++){switch(inputcharacters[j]) {//switch statement that check the input characters and outputs the correct morse
case 't' :
h=GT/3600;
m=(GT-h*3600)/60;
ss=GT-h*3600-m*60;
d[0]=(h/10);
d[1]=(h-(d[0]*10));
d[2]=(m/10);
d[3]=(m-(d[2]*10));
d[4]=(ss/10);
d[5]=(ss-(d[4]*10));
for(k=0;k<6;k++)
{while((IFG2 & 0x02)==0)
{;}
UCA0TXBUF=d[k]+48;
test[k]=d[k]+48;}
while((IFG2 & 0x02)==0)
{;}
UCA0TXBUF='r';
break;
case 'x' ://If this break case is not set to 's' it will not cause the error in the 't' case, no idea why
GT=0;
temp=(inputcharacters[j+1]-0x30)*10;//
temp+=(inputcharacters[j+2]-0x30);
GT+=(temp*3600);
temp=(inputcharacters[j+3]-0x30)*10;
temp+=(inputcharacters[j+4]-0x30);
GT+=(temp*60);
temp=(inputcharacters[j+5]-0x30)*10;
temp+=(inputcharacters[j+6]-0x30);
GT+=temp;
j+=7;
break;
case 'o' :
{;}
break;
case 'l' :
{;}
break;
case 'r' :
{;}
break;
default :
{i++;}
}}
i=0;
j=0;
}
else{i++;}}
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_interupt(void)
{
if(GT<86459)//24:00:59 in seconds
{GT++;}//add a second
else
{GT=60;}//00:01:00
if(timercount<299)//300s=5min
{timercount++;}
else{timercount=0;
ADC10CTL0 |= 0x3;// turn on ADC
while(ADC10CTL1 & ADC10BUSY)//loop to alow for ADC to finish sampeling
{;;}
ADC10CTL0 & 0xFFFE;//Shuting off the ADC after sampeling
tempature[i]=ADC10MEM;//Storing the tempature
tempaturetime[i]=GT;// storing the time
if(i<31)
{i++;}
else
{i=0;}
}
}
发布的代码的一个非常明显的问题是,当发现当前正在检查的输入字符x
时,必须在用户输入x
之后但在用户输入r
之前输入新的日期戳(作为 6 位数字),这可以工作,但没有代码强制执行该输入序列。
通常,UART 输入函数应包含多个"状态和子状态",其中命令 char 会导致代码切换到"状态",并且具有实际时间戳的子状态。 因此,当用户输入命令时,例如x
设置了模式,其中接下来输入的 6 位数字是新的时间戳。
建议设计一个"上下文敏感"的状态图,然后实现该图。
除此之外,输入缓冲区的大小将减少到 1 字节
在众多测序问题中,有一个事实是,当积累一些数字时,说这样的话
int temp = 0;
temp += inputchar[x] - 0x30;
temp += inputchar[x+1] - 0x30;
...
不会产生预期的结果。
将产生预期成果的是:
int temp = 0;
temp += inputchar[x] - 0x30;
temp = temp*10 + (inputchar[x+1] - 0x30);
....
temp = temp*10 + (inputchar[x+5] - 0x30);
GT = temp;
当然,在尝试将该输入应用于temp
计算之前,请使用 if( isdigit( inputchar[x] ) 测试每个输入字符
为了便于开发,强烈建议一次只尝试实现一个命令,并且当该命令正常工作时(广泛使用调试器以使测试变得容易,例如该芯片的jtag
调试器。 然后转到要实现的下一个命令。
变量i
正在两个中断处理程序中修改。 因此,当一个中断处理程序修改i
时,另一个中断的值被破坏。
一整天(24 小时)为 878400 秒,因此值 86459 不正确。 此外,这是代码中的"魔术"数字。 幻数没有根据。 "魔术"数字使代码更难理解、调试和维护。 建议使用enum
语句或#define
语句为该"魔术"数字提供一个有意义的名称,然后在整个代码中使用该有意义的名称。 注意:将GT
计数器重置为60是不正确的,在发布的代码中应将其重置为0。
对于"魔术"数字300也存在类似的考虑。
当输入命令被l
时,发布的代码没有任何操作,因此我们无法分析这种(不存在的)代码来确定它出了什么问题。
在处理t
命令时:
GT
变量可能会在访问之间进行修改。 建议保存到"新"变量,并从该新变量进行所有计算。
h
、m
和s
的计算正在对相同的中间变量进行大量的重新计算。 建议:
int myGT = GT;
h = myGT / 3600;
myGT %= 3600;
m = myGT / 60;
s = myGT % 60;
数组test[]
已设置,但未使用。 这是在生产代码中浪费资源。 建议它的存在和设置由一些-D
编译器参数确定。