一、项目介绍
本项目使用了 Code Composer Studio 软件和C语言编程,基于 TI F280049C LaunchPad 和硬禾学堂的输入输出扩展板,设计制作了一个智能温度调节展示系统。该系统利用温度传感器读取实际温度值,利用彩色LCD显示当前温度、设定的温度阈值以及加热状态,利用旋转编码器和按键实现对温度阈值的设置以及加热的开关,利用LED展示当前温度的大小状态。
二、设计思路
(1) LCD模块:使用五个GPIO引脚来模拟SPI通信,修改ST7735芯片的驱动,调用函数以实现显示当前温度、显示温度阈值、显示加热状态以及选中行的反色显示。
(2) RGB三色LED:通过三路GPIO输出高低电平,实现控制红、绿、蓝三个LED的亮灭,LED的亮灭规则体现在当前温度 temp 和温度阈值 t_lo,t_hi 的大小关系上。当 t_lo < t_hi 时,若 temp < t_lo,则只点亮蓝色LED;若 t_lo <= temp <= t_hi ,则只点亮绿色LED;若 temp > t_hi,则只点亮红色LED。当 t_lo = t_hi 时,若 temp 在 t_lo/t_hi 的 ±1℃ 的区间范围内,则只点亮绿色LED;若 temp 在该区间之下,则只点亮蓝色LED;若 temp 在该区间之上,则只点亮红色LED。
(3) 按键、旋转编码器模块:当不同动作发生时,R-2R电阻网络A_out处的电压大小不同。利用定时器25ms计时,驱动A/D转换,通过ADCINA1引脚读取AD值,再通过判断AD值的大小来分辨对应的动作。值得一提,扩展板PCB上电容C8的位置焊的是0R电阻,导致上按键K1被屏蔽,这里是焊了100nF电容上去,使K1可用。
(4) 温度传感器:使用两个GPIO引脚来模拟IIC通信,通过查阅NST112-DSTR的芯片手册并结合有关驱动资料,利用定时器定时500ms,调用函数读取芯片的温度寄存器的值,经转换得到当前温度值。
(5) 电阻加热模块:利用EPWM,通过EPWM5B引脚输出不同占空比的PWM波,实现对加热功率的控制。当打开加热开关后,使用PID算法控制输出的PWM波的占空比,实现较迅速且较稳定地调节温度值为设定的温度值 t_set。若 t_lo < t_hi,则 t_set = (t_lo + t_hi)/2;若 t_lo < t_hi,则 t_set = t_lo = t_hi。
(6) LaunchPad和扩展板的连接:画转接板并打板,用PCB和排针排母代替杜邦线来提高系统的稳定性。
三、硬件框图
四、硬件介绍
(1) TI F280049C LaunchPad
LAUNCHXL-F280049C 是一款适用于 TI C2000™ 实时控制器系列 F28004x 器件的低成本开发板。该器件不仅适用于初始评估和原型设计,还提供易于使用的标准化平台,用于开发下一个应用。该扩展版本 LaunchPad 可提供额外引脚用于开发,并支持连接两个 BoosterPack。作为庞大的 TI MCU LaunchPad 生态系统的一部分,该器件还与各种插件交叉兼容,包含 InstaSPIN-FOC 功能。
(2) 1.44 LCD 屏幕
彩色TFT-LCD屏幕,128*128像素,SPI接口,驱动芯片为ST7735。
(3)RGB LED
RGB三基色LED。
(4) NST112-DSTR 数字温度传感器
NST112是一款低功耗高精度数字温度传感器。适用于负温度系数和正温度系数热敏电阻的替换。NST112具有可兼容I2C和SMBus的接口,具有可编程报警和SMBus重置功能,在单路总线上最多可支持4个器件。且无需校准即可在 -20℃到85℃的范围内实现高达±0.5℃的精度。NST112温度传感器是高线性度的,不需要重新组合计算或查表以导出温度。NST112具有12bit的模数转换提供高达0.0625℃解析度。
(5) 按键/旋转编码器电路
5位R-2R电阻网络DAC,将动作转换为A_Out处的模拟电压。
(6) 电阻加热电路
控制V_HEAT的电平来控制NMOS的导通与截止,实现对流过电阻的电流的控制,进而控制电阻的加热功率。
(7) 转接板
使用嘉立创绘制PCB与打样,原理图和PCB如下。
五、部分代码
(1) LED亮灭
LED的亮灭规则体现在当前温度 temp 和温度阈值 t_lo,t_hi 的大小关系上。
void LED_Show(unsigned int t_lo, unsigned int t_hi, float temp)
{
if(t_lo < t_hi)//不相等,区间内才亮绿灯
{
if((int)temp < t_lo){LED_BLUE;}
else if( t_lo <= (int)temp && (int)temp <= t_hi ){LED_GREEN;}
else if(temp > t_hi){LED_RED;}
}
else if(t_lo == t_hi)//相等,误差在 ±1°C 内时才亮绿灯
{
if( (temp-(float)t_lo) < -1.0 ){LED_BLUE;}
else if( -1.0 <= (temp-(float)t_lo) && (temp-(float)t_lo) <= 1.0 ){LED_GREEN;}
else if( (temp-(float)t_lo) > 1.0 ){LED_RED;}
}
}
(2) 温度读取
根据NST112-DSTR的芯片手册及有关资料,按照时序图编写读温度寄存器的函数。
float NST112_Read_Temp(void)
{
unsigned int tem = 0, hum = 0;
unsigned char msb = 0, lsb = 0;
float Temp = 0;
I2C_Start();
I2C_WriteByte(NST112_ADDRESS << 1 | 0);
I2C_WaitAck();
I2C_WriteByte(NST112_REG_Temp);
I2C_WaitAck();
I2C_Delay(1);
I2C_Start();
I2C_WriteByte(NST112_ADDRESS << 1 | 1);
if( I2C_WaitAck() == 0 )
{
msb = I2C_ReadByte();
I2C_Ack();
I2C_SDA_H;//拉高SDA
lsb = I2C_ReadByte();
I2C_NoAck();
I2C_Stop();
}
else
{
msb = 0;
lsb = 0;
I2C_Stop();
}
if(msb & 0x80)
{
tem = (msb << 8) | lsb ;
hum = (((~tem) >> 4) + 1) & 0x0fff;
Temp = -(float)(hum * 0.0625);
}
else
{
tem = (msb << 8) | lsb ;
hum = tem >> 4;
Temp = (float)(hum * 0.0625);
}
return Temp;
}
(3) A/D转换与动作判断
软件SOC,ADC单通道多次采样,求均值再判断。
char ADC_GetState(void)
{
unsigned int i, A_out = 0;
char state = 0;
for(i=0;i<=6;i++)//软件触发adc,一次采10个数据
{
ADC_forceSOC(ADC_Aout_BASE, ADC_SOC_NUMBER1);
A_out += ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER1);
}
A_out /= 7;//求平均值
if(3090 < A_out && A_out < 3150) {state = 0;}//3100
else if(2990 < A_out && A_out < 3030) {state = 1;}//3000
else if(2880 < A_out && A_out < 2940) {state = 2;}//2900
else if(2600 < A_out && A_out < 2800) {state = 3;}//2700
else if(2200 < A_out && A_out < 2490) {state = 4;}//2290
else if(1400 < A_out && A_out < 1700) {state = 5;}//1500
return state;
}
(4) 位置式PID算法控制EPWM输出不同占空比、频率恒为1kHz的PWM波,实现温度调节。
float PID_GetDuty(float tact, float tset)
{
pid_temp.set = tset;
pid_temp.actual = tact;
pid_temp.ero_new = pid_temp.set - pid_temp.actual;//计算误差
pid_temp.itgl = pid_temp.itgl + pid_temp.ero_new;//计算积分
pid_temp.res = pid_temp.k_p * pid_temp.ero_new
+ pid_temp.k_i * pid_temp.itgl
+ pid_temp.k_d * (pid_temp.ero_new - pid_temp.ero_old);
pid_temp.ero_old = pid_temp.ero_new;//保存误差
pid_temp.duty = pid_temp.res + 0.00;
Limit(pid_temp.duty, 0.0, 0.90);
return pid_temp.duty;
}
void EPWM_SetDuty(float duty)//CLK=10MHz, count_down, PRD=10000, duty->0.01(0<=duty<=1.00)
{
unsigned int cmpmin = 0, cmpmax = 9000;
unsigned int cmp = (unsigned int)(10000 * duty);
//unsigned int cmpvalue;
//cmpvalue = EPWM_getCounterCompareValue(EPWM_PWMout_BASE, EPWM_COUNTER_COMPARE_B);
if(cmpmin <= cmp && cmp <= cmpmax)
{
EPWM_setCounterCompareValue(EPWM_PWMout_BASE, EPWM_COUNTER_COMPARE_B, cmp);
}
}
六、遇到的主要难题
(1)初次接触 TI 的 LaunchPad,不知道如何上手,不习惯阅读英文资料。
解决方法:学习并移植 C2000Ware 的 F280049C 例程。
(2)移植STM32的LCD驱动时,lcd_font.h文件的const常量所需空间过大,存储器分区放不下,导致工程不能成功编译。
解决方法:学习.cmd文件,修改了.const等的分区,删除了部分用不上的const常量。
(3)NST112-DSTR的资料非常少,无法成功读取温度。
解决方法:仔细阅读芯片手册、花了非常多的时间去调试,才成功读出了温度寄存器的MSB和LSB。
(4)对ADC的时钟和采样窗口不熟悉,不会ADC滤波,得到的结果与仿真结果相对误差比较大。
解决方法:使用了朴素的求平均值的方法。
(5)不熟悉位置式PID算法,调出来的效果不理想。
解决方法:耐心地由Kp到Ki到Kd,每次调试都只调整一个参数,且每次调整量尽量小,同时通过Watch Expressions观察变量。
(6)全英文的 c2000.syscfg 的资料非常的少,配置时难以保证效率。
解决方法:参考 C2000Ware 的 F280049C 例程的 c2000.syscfg的配置。
七、未来的计划
(1)深入学习PID算法,调出更好的控温效果。
(2)学习 F280049C 的其他模块,如CLA,SCI,CLB等。
(3)学习 F280049C 的RAM和FLASH,充分发挥其性能。
(4)使用ECAP捕获扩展板上双电位计摇杆电路输出的PWM波。
(5)尝试完成平台9的任务一:交互式运动反馈系统。
(6)多使用TI的平台,将活动过程所学运用于电赛的赛题中。