一.项目描述
项目需求:
设计一个基于温度变化的展示系统。温度传感器检测温度变化,彩色LCD显示当前温度和设定阈值。LED根据温度高低展示不同颜色。按键用于设置温度阈值,摇杆调节LED显示的模式和控制参数。
实现功能:
在LCD上绘制仪表盘显示实时温度,同时可通过摇杆、按键修改温度上下限、RGB-LED显示模式、恒温功能开启、恒温温度等参数。将温度曲线通过串口上传至上位机绘制曲线。
接线方式:
注意事项:本次我用的显示按键模块(黑色的那块)是以前参加funpack活动的,和本次活动的同款,但两个按键都是好的,所以我程序里用上了两个按键。本次配发的黑色板子有一个按键是短路的,用着有问题,不适合我的程序。一定要用两个按键都是好的才行。
二.设计思路
①开发板、拓展板
开发板使用TMS320F280049的LAUCHPAD评估板,该芯片是C2000系列实时控制芯片,100MHz主频,32位硬件浮点,3.45MHz ADC,256KB ROM,100KB RAM,有高精度定时器EPWM、ECAP等功能,适合应用于数字电源、电机控制。
扩展板如下图所示,包含:①按键、旋转编码器输入 - 以模拟信号的方式②双电位计控制输入 - 以数字信号的方式③RGB三色LED显示④1.44寸128*128 LCD,SPI总线访问⑤电阻加热⑥温度传感器
②开发环境配置
这款DSP支持使用sysconfig进行配置,sysconfig可使用下拉框进行配置,拥有sysconfig甚至可以不看数据手册直接上手该DSP,相比于TMS320F28335这些老DSP用手配寄存器的开发方式,有sysconfig外加寄存器库,开发效率可以快速提升。
在安装好CCS和C2000ware之后,可以打开CCS,按下图的路径导入示例工程,可以在示例上进行改造,免去新建工程的繁琐过程。
打开工程后,可以在右侧工具栏看到.syscfg文件,该文件就是sysconfig图形化配置的文件
双击打开就可以弹出如下配置窗口
③按键检测原理
如上为按键部分原理图。通过一个io口输出数字量从而读取按键组合。该电路图上有100k和200k电阻,让我想到了R2R的DAC网络结构。那么根据R2R的原理,五个按键可以当作五个开关,那么就会有5bit分辨率的电压输出。而我们采集的时候是用adc进行采集,adc在单片机中本质也是二进制,所以我选择只用280049DSP中软件触发ADC的模式,然后取出12位AD结果的高五位,那么每一位的0或1结果就代表着对应的按键,从而可以识别出哪一个按键按下了。主程序循环中使用查询法。本次我用的显示按键模块(黑色的那块)是以前参加funpack活动的,和本次活动的同款,但两个按键都是好的,所以我程序里用上了两个按键。本次配发的黑色板子有一个按键是短路的,用着有问题,不适合我的程序。一定要用两个按键都是好的才行。主程序部分如下。
ADC_forceMultipleSOC(myADC0_BASE, ADC_FORCE_SOC0);
while(ADC_getInterruptStatus(myADC0_BASE, ADC_INT_NUMBER1) == false);//等待AD转换完成
ADC_clearInterruptStatus(myADC0_BASE, ADC_INT_NUMBER1);//清中断标志
myADC0Result0 = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);//读ADC值
a1=myADC0Result0&0x800;//取最高位为第一个按键状态
a2=myADC0Result0&0x400;//取次高位为第二个按键状态
④摇杆部分
摇杆部分的电路图如上图。摇杆本质上是两个电位器,U2D是滞回比较器,U2A是积分器,二者合起来是三角波发生器,改变X轴就可以改变积分常数,从而改变频率。U2B是比较器,改变Y轴就可以改变分压电阻,从而改变5脚电压,这样可以改变占空比。
使用ECAP模块捕获上升沿和下降沿,进行运算后即可得到频率和占空比,代码如下。
cap1cnt = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_1);;
cap2cnt = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_2);;
cap3cnt = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_3);;
cap4cnt = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_4);;
Period1 = cap3cnt - cap1cnt;
Period2 = cap2cnt - cap1cnt;
duty=100*Period2/Period1;
⑤NST112的读取
NST112通过数据手册可以看到使用的是i2c协议进行通信的。那么本次我使用io口模拟i2c的方式,没有使用硬件i2c,因为读温度数据短,不需要很高速度,用软件i2c便于移植。
在板子上ADD0脚连接GND了,所以设备地址是1001000,所以设备地址为0x48,我程序里定义的需要左移1位,所以是0x90。
上图是内部地址。寄存器地址只需要0x00配置寄存器,在初始化的时候使用,0x01为读温度寄存器,每次采集温度的时候访问0x01读两个字节。
上图是0x00配置寄存器,在初始化的时候发两个字节配置一下即可,我设置8Hz采样。初始化程序如下。
void NST112_configuration(){
char hh[2]={0x60,0xE0}; //8Hz
I2C_SAND_BUFFER(0x90, 0x01,hh,2);
}
读取和数据拼接如下。
I2C_READ_BUFFER(0x90,0x00,buf,2);
now_t=buf[0]*256+buf[1];
now_t=now_t>>4;
⑥加热的控制
加热电阻在PCB的下方,温度传感器在pcb的上方检测温度,温度传感器检测温度,经DSP进行PID运算后控制加热电阻。pid核心代码如下。
float increment_pid(float error,pid_info *pid)//增量式PID
{
pid->error = error;
pid->dError = error - pid->lastError;
pid->ddError = pid->dError - pid->dError_last;
pid->lastError = error;
pid->dError_last = pid->dError;
pid->output =(pid->kp*pid->dError)+(pid->ki*error)+(pid->kd*pid->ddError) + pid->output_last;
pid->output_last = pid->output;
if((pid->output)>10000)pid->output=10000;
if((pid->output)<0)pid->output=0;
return pid->output;
}
⑦屏幕的驱动
使用sysconfig配置硬件spi,之后直接套用st7735的驱动程序。显示数字、字母使用现成的函数。如下是绘制温度仪表盘的程序。
#define radius 63
#define X_CENTER 63
#define Y_CENTER 63
int x1, y1, x2, y2 , x3 , y3;
double angle;
void draw(int last,int now) {
signed int i,j;
angle = (last*4.5+225)* 0.0174533;
x2 = X_CENTER + (sin(angle) * (radius - 1));
y2 = Y_CENTER - (cos(angle) * (radius - 1));
x3 = X_CENTER + (sin(angle) * 30);
y3 = Y_CENTER - (cos(angle) * 30);
LCD_DrawLine(x3,y3,x2,y2,BLACK);//清除上一次指针
Draw_Circle(X_CENTER, Y_CENTER, 30,WHITE);//表针中心
Draw_Circle(X_CENTER, Y_CENTER, 63,WHITE);//表盘外圈
Draw_Circle(X_CENTER, Y_CENTER, 64,WHITE);//表盘外圈
for(j=0; j<7; j++){
angle = (j*45+45)* 0.0174533;
x1 = X_CENTER + (sin(angle) * radius);
y1 = Y_CENTER + (cos(angle) * radius);
x2 = X_CENTER + (sin(angle) * (radius - 6));
y2 = Y_CENTER + (cos(angle) * (radius - 6));
LCD_DrawLine(x1,y1,x2,y2,WHITE);//刻度盘
x2 = X_CENTER - (sin(angle) * (radius - 15));
y2 = Y_CENTER + (cos(angle) * (radius - 15));
LCD_ShowIntNum(x2-7, y2-8,j*10,2,YELLOW,BLACK,16);//显示整数变量
}
angle = (now*4.5+225)* 0.0174533;
x2 = X_CENTER + (sin(angle) * (radius - 1));
y2 = Y_CENTER - (cos(angle) * (radius - 1));
x3 = X_CENTER + (sin(angle) * 30);
y3 = Y_CENTER - (cos(angle) * 30);
LCD_DrawLine(x3,y3,x2,y2,WHITE);//指针
}
⑧串口部分
使用sysconfig配置串口初始化,可以使用如下代码定义一个printf,然后就可以使用printf进行串口输出,更方便。
void UART_printf (char *fmt, ...){
char buffer[30]; // 数据长度
unsigned char i = 0;
va_list arg_ptr;
va_start(arg_ptr, fmt);
vsnprintf(buffer, 31, fmt, arg_ptr);
while ((i < 30) && (i < strlen(buffer))){
SCI_writeCharBlockingNonFIFO(mySCI0_BASE,(unsigned char) buffer[i++]);
}
va_end(arg_ptr);
}
可以使用Arduino的串口绘图器绘制曲线,但是需要按照格式进行发送。
UART_printf("%d,%d\r\n",set_T*16,now_t);
最终可以绘制出如下曲线,利用曲线可以更方便调整PID参数。
⑨RGB-LED的驱动
使用EPWM生成三路10kHz的PWM。为了实现彩灯渐变效果,可以使用HSV转RGB。这样只要改变色相H参数在0~360之间生成的就是渐变色。HSV转RGB代码如下。
float H,S=1,V=1;
int r,g,b;
void hsv2rgb(float h, float s, float v)
{
if(h<720&&h>=360)h=h-360;
int hi = ((int)h / 60) % 6;
float f = h * 1.0 / 60 - hi;
float p = v * (1 - s);
float q = v * (1 - f * s);
float t = v * (1- (1 - f) * s);
switch (hi){
case 0:
r = 10000 * v;
g = 10000 * t;
b = 10000 * p;
break;
case 1:
r = 10000 * q;
g = 10000 * v;
b = 10000 * p;
break;
case 2:
r = 10000 * p;
g = 10000 * v;
b = 10000 * t;
break;
case 3:
r = 10000 * p;
g = 10000 * q;
b = 10000 * v;
break;
case 4:
r = 10000 * t;
g = 10000 * p;
b = 10000 * v;
break;
case 5:
r = 10000 * v;
g = 10000 * p;
b = 10000 * q;
break;
}
}
三.整体设计
最近学习了一下freertos操作系统,正好拿这个项目来实操练习一下。创建三个task,task1负责按键扫描,50ms一个扫描周期,保证按键检测的及时响应,优先级设为1,这样空闲的时候就执行task1扫描按键。task2负责控制RGB彩灯和液晶屏的超限显示,200ms一个扫描周期。task3是检测温度,显示参数、pid控制,因为对时间要求比较高,所以选择最高优先级,使用vTaskDelayUntil保证125ms一次周期。
四.最终成品
五.总结
通过本次寒假在家一起练活动,熟悉了tms320f280049的开发,同时也借此机会学了一下freertos实时操作系统。这款DSP芯片强大的EPWM和ADC功能非常适用于电气工程专业的数字电源和电机控制方面的开发,希望后面可以用这套板卡完成更高级的项目。