1、功能介绍
1、温度传感器检测温度变化,LCD显示当前温度和设定温度。
2、LED当设定温度与当前温度不超过5度时,亮绿灯,否则,亮红灯。
3、摇杆和按键用来调节设定温度和是否开启加热。
2、设计思路
2.1、设计思路
1、用ADC获取按键通过电阻网络输出的电平值
2、用输入捕获获取摇杆通过运放电路输出的PWM的频率和占空比
3、通过SPI驱动LCD,通过I2C获取温度传感器的温度值
4、输出PWM控制加热模块
5、使用一个定时器进行获取键值和当前温度
2.2、流程图
3、程序实现
1、按键
由于有一个按键在硬件电路上被屏蔽了,使用旋转编码器代替。
1.1、硬件资源
引脚 | 功能 |
---|---|
ADCINA0 | 获取电阻网络输出的电平值 |
1.2、初始化设置
设置电压基准源:选择内部的1.65V电源
时钟源:选择系统时钟,再进行2分频
引脚选择:选择ADCA的IN0引脚
1.3、程序编写
ADC获取的是一个12位数据,为了方便,就没有转化为电压值,直接使用了原始数据来进行判断。
下面是判断键值的代码,写在定时器中断中。
//获取按键电压值
ADC_forceMultipleSOC(myADC0_BASE, (ADC_FORCE_SOC0 | ADC_FORCE_SOC1));
while(ADC_getInterruptStatus(myADC0_BASE, ADC_INT_NUMBER1) == false)
{
}
ADC_clearInterruptStatus(myADC0_BASE, ADC_INT_NUMBER1);
KeyValue = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
//分配键值
if(KeyValue >=2400){
Key_flag = 0;
}else if(KeyValue >=2000 && KeyValue < 2200){
Key_flag = 2;
}else if(KeyValue >=700 && KeyValue < 900){
Key_flag = 1;
}
2、摇杆
2.1、硬件资源
引脚 | 功能介绍 |
---|---|
GPIO7 | 获取运放网络输出PWM的频率和占空比 |
2.2、初始化设置
引脚:通过Xbar将GPIO7输入引脚映射到ECAP1
时钟源:默认系统时钟
触发事件配置:事件1捕获下降沿,事件2捕获上升沿,事件3捕获下降沿,事件4捕获上升沿,
中断源选择:事件4
计数器复位:使能,4个事件都触发
2.3、程序编写
在实际的程序编写中,只用到前面两个事件。
下面是输入捕获的中断函数,用于获取PWM的频率和占空比。
__interrupt void INT_myECAP0_ISR(void)
{
cap1Count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_1);
cap2Count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_2);
cap3Count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_3);
cap4Count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_4);
Duty_get = cap1Count * 100.0 / (cap1Count + cap2Count) + 0.5;
Fre_get = 100000000.0 / (cap1Count + cap2Count);
//遥杆上下
if(Duty_get >= 32 && Duty_get <= 35){
Rocker_flag = 1;
}else if(Duty_get >= 56 && Duty_get <= 58){
Rocker_flag = 0;
}else if(Duty_get >= 80 && Duty_get <= 90){
Rocker_flag = 2;
}
//摇杆左右
/* if(Fre_get >= 200 && Fre_get <= 250){
LED_SetColor(1);
}else if(Fre_get >= 280 && Fre_get <= 320){
LED_SetColor(2);
}else if(Fre_get >= 420 && Fre_get <= 460){
LED_SetColor(3);
}*/
ECAP_clearInterrupt(myECAP0_BASE,ECAP_ISR_SOURCE_CAPTURE_EVENT_4);
ECAP_clearGlobalInterrupt(myECAP0_BASE);
//
// Start eCAP
//
ECAP_reArm(myECAP0_BASE);
//
// Acknowledge the group interrupt for more interrupts.
//
Interrupt_clearACKGroup(INT_myECAP0_INTERRUPT_ACK_GROUP);
}
cap1Count表征高电平时长对应的计数值,cap2Count表征低电平时长对应的计数值。
用系统时钟的频率100M除以二者之和,得到PWM的频率。
用高电平时长对应的计数值除以二者之和,得到PWM的占空比,根据表达习惯,将得到的值乘以100,让占空比的单位变为%。
3、LCD
3.1、硬件资源
使用模拟SPI
引脚 | 定义 | 功能介绍 |
---|---|---|
GPIO57 | LCD_SCL | 时钟线 |
GPIO16 | LCD_SDA | 数据线 |
GPIO17 | LCD_RST | 复位线 |
GPIO39 | LCD_DC | 控制线 |
GPIO59 | LCD_CS | 片选 |
3.2、初始化配置
GPIO:配置为输出
3.3、程序编写
使用的往期活动案例的代码,原来的硬件平台是MSP430,只要将引脚定义和输出函数修改一下就能使用。
如下。
//-----------------LCD端口定义----------------
#define LCD_SCLK_Clr() GPIO_writePin(myLCD_SCL, 0);//SCL=SCLK
#define LCD_SCLK_Set() GPIO_writePin(myLCD_SCL, 1);
#define LCD_MOSI_Clr() GPIO_writePin(myLCD_SDA, 0);//SDA=MOSI
#define LCD_MOSI_Set() GPIO_writePin(myLCD_SDA, 1);
#define LCD_RES_Clr() GPIO_writePin(myLCD_RST, 0);//RES
#define LCD_RES_Set() GPIO_writePin(myLCD_RST, 1);
#define LCD_DC_Clr() GPIO_writePin(myLCD_DC, 0);//DC
#define LCD_DC_Set() GPIO_writePin(myLCD_DC, 1);
#define LCD_CS_Clr() GPIO_writePin(myLCD_CS, 0);//CS
#define LCD_CS_Set() GPIO_writePin(myLCD_CS, 1);
另外,使用二级菜单来实现调节温度的设定值和启用和关闭加热电路。
void get_page(void)
{
if(Page == 1 && Home_sec == 0 && Key_flag == 1){
Page = 21;
}else if(Page == 1 && Home_sec == 1 && Key_flag == 1){
Page = 22;
}else if(Page == 1 && Home_sec == 2 && Key_flag == 1){
Page = 23;
}else if((Page == 21 || Page == 22 || Page == 23) && Key_flag == 2){
Page = 1;
}
}
通过上述函数得到页面标志位。
void GUI_display(void)
{
switch(Page)
{
case 1:
GUI_1();
break;
case 21:
GUI_21();
break;
case 22:
// GUI_22();
break;
case 23:
GUI_23();
break;
}
}
再通过上述函数进行页面的刷新。
另外,由于这块板卡在给定的例程中,定义的RAM比较小,使用字符库lcdfont.h时,会出现空间不够用的情况,只要在ram.cmd文件中分配足够大的空间就可以了。
MEMORY
{
PAGE 0 :
/* BEGIN is used for the "boot to SARAM" bootloader mode */
BEGIN : origin = 0x000000, length = 0x000002
RAMM0 : origin = 0x0000F6, length = 0x00030A
RAMLS0 : origin = 0x008000, length = 0x000800
RAMLS1 : origin = 0x008800, length = 0x000800
RAMLS2 : origin = 0x009000, length = 0x000800
RAMLS3 : origin = 0x009800, length = 0x000800
RAMLS4 : origin = 0x00A000, length = 0x000800
RESET : origin = 0x3FFFC0, length = 0x000002
/* Flash sectors: you can use FLASH for program memory when the RAM is filled up*/
/* BANK 0 */
FLASH_BANK0_SEC0 : origin = 0x080000, length = 0x002000 /* on-chip Flash */
// FLASH_BANK0_SEC1 : origin = 0x081000, length = 0x001000 /* on-chip Flash */
FLASH_BANK0_SEC2 : origin = 0x082000, length = 0x001000 /* on-chip Flash */
FLASH_BANK0_SEC3 : origin = 0x083000, length = 0x001000 /* on-chip Flash */
FLASH_BANK0_SEC4 : origin = 0x084000, length = 0x001000 /* on-chip Flash */
FLASH_BANK0_SEC5 : origin = 0x085000, length = 0x001000 /* on-chip Flash */
FLASH_BANK0_SEC6 : origin = 0x086000, length = 0x001000 /* on-chip Flash */
FLASH_BANK0_SEC7 : origin = 0x087000, length = 0x001000 /* on-chip Flash */
FLASH_BANK0_SEC8 : origin = 0x088000, length = 0x001000 /* on-chip Flash */
FLASH_BANK0_SEC9 : origin = 0x089000, length = 0x001000 /* on-chip Flash */
FLASH_BANK0_SEC10 : origin = 0x08A000, length = 0x001000 /* on-chip Flash */
FLASH_BANK0_SEC11 : origin = 0x08B000, length = 0x001000 /* on-chip Flash */
FLASH_BANK0_SEC12 : origin = 0x08C000, length = 0x001000 /* on-chip Flash */
FLASH_BANK0_SEC13 : origin = 0x08D000, length = 0x001000 /* on-chip Flash */
FLASH_BANK0_SEC14 : origin = 0x08E000, length = 0x001000 /* on-chip Flash */
FLASH_BANK0_SEC15 : origin = 0x08F000, length = 0x001000 /* on-chip Flash */
PAGE 1 :
BOOT_RSVD : origin = 0x000002, length = 0x0000F1 /* Part of M0, BOOT rom will use this for stack */
RAMM1 : origin = 0x000400, length = 0x0003F8 /* on-chip RAM block M1 */
// RAMM1_RSVD : origin = 0x0007F8, length = 0x000008 /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
RAMLS5 : origin = 0x00A800, length = 0x001800
// RAMLS6 : origin = 0x00B000, length = 0x000800
// RAMLS7 : origin = 0x00B800, length = 0x000800
RAMGS0 : origin = 0x00C000, length = 0x002000
RAMGS1 : origin = 0x00E000, length = 0x002000
RAMGS2 : origin = 0x010000, length = 0x002000
RAMGS3 : origin = 0x012000, length = 0x001FF8
// RAMGS3_RSVD : origin = 0x013FF8, length = 0x000008 /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
/* BANK 1 */
FLASH_BANK1_SEC0 : origin = 0x090000, length = 0x002000 /* on-chip Flash */
// FLASH_BANK1_SEC1 : origin = 0x091000, length = 0x001000 /* on-chip Flash */
FLASH_BANK1_SEC2 : origin = 0x092000, length = 0x001000 /* on-chip Flash */
FLASH_BANK1_SEC3 : origin = 0x093000, length = 0x001000 /* on-chip Flash */
FLASH_BANK1_SEC4 : origin = 0x094000, length = 0x001000 /* on-chip Flash */
FLASH_BANK1_SEC5 : origin = 0x095000, length = 0x001000 /* on-chip Flash */
FLASH_BANK1_SEC6 : origin = 0x096000, length = 0x001000 /* on-chip Flash */
FLASH_BANK1_SEC7 : origin = 0x097000, length = 0x001000 /* on-chip Flash */
FLASH_BANK1_SEC8 : origin = 0x098000, length = 0x001000 /* on-chip Flash */
FLASH_BANK1_SEC9 : origin = 0x099000, length = 0x001000 /* on-chip Flash */
FLASH_BANK1_SEC10 : origin = 0x09A000, length = 0x001000 /* on-chip Flash */
FLASH_BANK1_SEC11 : origin = 0x09B000, length = 0x001000 /* on-chip Flash */
FLASH_BANK1_SEC12 : origin = 0x09C000, length = 0x001000 /* on-chip Flash */
FLASH_BANK1_SEC13 : origin = 0x09D000, length = 0x001000 /* on-chip Flash */
FLASH_BANK1_SEC14 : origin = 0x09E000, length = 0x001000 /* on-chip Flash */
FLASH_BANK1_SEC15 : origin = 0x09F000, length = 0x001000 /* on-chip Flash */
}
SECTIONS
{
codestart : > BEGIN, PAGE = 0
.TI.ramfunc : > RAMM0, PAGE = 0
.text : >> RAMLS0 | RAMLS1 | RAMLS2 | RAMLS3 | RAMLS4 | FLASH_BANK0_SEC0, PAGE = 0
.cinit : > RAMM0, PAGE = 0
.switch : > RAMM0, PAGE = 0
.reset : > RESET, PAGE = 0, TYPE = DSECT /* not used, */
.stack : > RAMM1, PAGE = 1
#if defined(__TI_EABI__)
.bss : > RAMLS5 | FLASH_BANK1_SEC0, PAGE = 1
.bss:output : > RAMLS5, PAGE = 1
.init_array : > RAMM0, PAGE = 0
.const : > RAMLS5 | RAMGS0 | FLASH_BANK1_SEC0, PAGE = 1
.data : > RAMLS5 | FLASH_BANK1_SEC0, PAGE = 1
.sysmem : > RAMLS5, PAGE = 1
.bss:cio : > RAMLS0, PAGE = 0
#else
.pinit : > RAMM0, PAGE = 0
.ebss : > RAMLS5, PAGE = 1
.econst : > RAMLS5, PAGE = 1
.esysmem : > RAMLS5, PAGE = 1
.cio : > RAMLS0, PAGE = 0
#endif
ramgs0 : > RAMGS0, PAGE = 1
ramgs1 : > RAMGS1, PAGE = 1
}
MEMORY中的FLASH_BANK都是可以使用的。
4、温度传感器
4.1、硬件资源
使用的是模拟I2C。
引脚 | 定义 | 功能介绍 |
---|---|---|
GPIO37 | I2C_SCL | 时钟线 |
GPIO35 | I2C_SDA | 数据线 |
4.2、初始化配置
GPIO:配置为输出
4.3、程序编写
使用的往期活动案例的代码,原来的硬件平台是MSP430,只要将引脚定义和输出函数修改一下就能使用。
如下。
#define SCL_H GPIO_writePin(myI2C_SCL, 1)
#define SCL_L GPIO_writePin(myI2C_SCL, 0)
#define SDA_H GPIO_writePin(myI2C_SDA, 1)
#define SDA_L GPIO_writePin(myI2C_SDA, 0)
#define SDA_OUT GPIO_setDirectionMode(myI2C_SDA, GPIO_DIR_MODE_OUT)
#define SDA_IN GPIO_setDirectionMode(myI2C_SDA, GPIO_DIR_MODE_IN)
#define SDA_GET GPIO_readPin(myI2C_SDA)
以下是读取温度传感器的函数,返回值是当前温度值。
float Read_NST112_Temp(void)
{
int Origin_Temp = I2C_ReadReg(NST112_ADDRESS,NST112_REG_Temp);
float Temp;
Temp = (char)(Origin_Temp>>8);
unsigned char decimal=(unsigned char)Origin_Temp;
if(Temp>=0)
Temp += (float)(decimal>>4)/16;
else
Temp -= (float)(((~decimal)>>4)+1)/16;
return Temp;
}
5、加热
5.1、硬件资源
引脚 | 功能介绍 |
---|---|
GPIO0 | 输出PWM波以控制加热电路 |
5.2、初始化配置
时基单元:对系统时钟4分频,计数模式选择向上计数模式,周期值设置为25000,此时频率为1kHz。
比较单元:比较值的初值设置为0,通过改变比较值,可以改变输出PWM的占空比。
动作单元:选择事件为输出高电平
5.3、程序编写
通过改变输出PWM的占空比,能够控制加热电路的功率。由于加热电路与温度传感器之间的热传递比较缓慢,容易加热过度,所以若当前温度超过了设定温度,占空比设置为应有的十分之一。
void Heat_on()
{
//加热
if(heat_state == 1){
if(pid_T.ActualT < pid_T.SetT){
Duty = PID_realize(pid_T.SetT,pid_T.ActualT);
EPWM_setCounterCompareValue(myHeat_BASE, EPWM_COUNTER_COMPARE_A, (uint16_t)(Duty * 250));
}else{
EPWM_setCounterCompareValue(myHeat_BASE, EPWM_COUNTER_COMPARE_A, (uint16_t)(Duty * 50));
}
}
}
其中,通过PID计算得到应该输出的占空比。
float PID_realize( float v, float v_r)
{
pid_T.SetT = v;
pid_T.ActualT = v_r; // 实际传入 = ADC_Value * 3.3f/ 4096
pid_T.err = pid_T.SetT - pid_T.ActualT; //计算偏差
pid_T.integral = (pid_T.integral*(pid_T.Times-1) + pid_T.err)/pid_T.Times; //积分求和
LIMIT(pid_T.integral,-pid_T.integral_limit,pid_T.integral_limit);
pid_T.result = pid_T.Kp * pid_T.err + pid_T.Ki * pid_T.integral + pid_T.Kd * ( pid_T.err - pid_T.err_last);//位置式公式
pid_T.err_last = pid_T.err; //留住上一次误差
pid_T.Pwr=25+pid_T.result;
LIMIT(pid_T.Pwr,10,pid_T.result_limit);
return pid_T.Pwr;
}
6、定时器
6.1、硬件资源
CPUTIMER2
6.2、初始化配置
时间周期:2的32次方
中断:使能
定时器开启:不开启,在主函数中开启
6.3、程序编写
开启定时器,并配置中断周期
configCPUTimer(myCPUTIMER2_BASE, DEVICE_SYSCLK_FREQ, 500000);
在中断函数里获取键值和当前温度
__interrupt void INT_myCPUTIMER2_ISR(void)
{
//获取按键电压值
ADC_forceMultipleSOC(myADC0_BASE, (ADC_FORCE_SOC0 | ADC_FORCE_SOC1));
while(ADC_getInterruptStatus(myADC0_BASE, ADC_INT_NUMBER1) == false)
{
}
ADC_clearInterruptStatus(myADC0_BASE, ADC_INT_NUMBER1);
KeyValue = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
//分配键值
if(KeyValue >=2400){
Key_flag = 0;
}else if(KeyValue >=2000 && KeyValue < 2200){
Key_flag = 2;
}else if(KeyValue >=700 && KeyValue < 900){
Key_flag = 1;
}
//获取温度值
pid_T.ActualT = Read_NST112_Temp();
//温度判断
t_dif = pid_T.SetT - pid_T.ActualT;
if(t_dif >= -5 && t_dif <= 5){
LED_SetColor(2); //绿灯
}else{
LED_SetColor(1); //红灯
}
}
4、遇到的主要困难
1、该平台的硬件SPI比较难配置,所以使用模拟SPI。
2、RAM空间分配不足,可以通过修改cmd文件实现。