功能简介
本项目是基于AVR64DD32 Curiosity Nano核心板和IOBV3-MSP430扩展板的加热及温度采集系统。项目主要用到的单片机外设有ADC、I2C、SPI、PWM、UART和GPIO,包含的硬件有LCD屏、nst112温度传感器、LED灯和按键。
实现思路
通过SPI来控制屏幕的显示,PWM驱动加热电阻进行加热,通过I2C跟温度传感器通讯进行温度数据采集,通过ADC采集扩展版的按键模拟信号来判断哪个按键按下,然后通过不同的按键来选择不同的功能或模式。UART作为日志信息输出接口,打印一下参数信息。
框图(当前设备环境无法上传文件,只能这么绘制了):
```c
/*
+-------+
+-- | START |
/ +-------+
\|/
+-----+ +------------+ +------------+ +-------------+ +-------------------+
| INIT | --> | BTN Check | --> | read temp | --> | LED control | --> | draw temp wave |
+-----+ +------------+ +------------+ +-------------+ +-------------------+
/|\ |
\ +---------------+ +--------------+ /
+-- | Update PWM | <-- | BTN process | <-+
+---------------+ +---------------+
*/
```
硬件连接
硬件的连接如下:
LED1接到了PF4,LED2接到了PF3,LED3接到了PC2;
SPI使用的默认的PORTMUX配置,接口是:
- LCD_SCL接到了PA6
- LCD_SDA接到了PA4
- LCD_CS接到了PA7
还有LCD的其他引脚:
- LCD_RST接到了PC3
- LCD_DC接到了PD2
温度传感器使用的引脚是:
- IIC_SCL接到了PA3
- IIC_SDA接到了PA2
PWM引脚使用的是:
- V_HEAT接到了PF2,用来控制加热电阻工作。
ADC使用的引脚是:
- AOUT接到了PD1,接到了按键,不同的按键对应的输出电压是不一样的,OK键的ADC值大概是3500,UP键对应的是2900,DOWN键对应的是1900。
扩展板和核心板使用杜邦线连接。
代码分析
首先是主函数,下面的代码删掉了部分变量申明,具体的可以查看源码:
int main(void) {
sysclk_init();
board_init();
uint8_t tmp = 0x06;
i2c_send_bytes(0, 0, &tmp, 1);
uint8_t mask = i2c_device_check(0, 0x48, 0x4C);
uart_printf(0, "mask:%02x\n", mask);
/* 检查温度传感器的地址 */
for(int i=0; i<4; i++)
{
if(mask & (1 << i))
{
drv_nst112_init(0x48+i);
break;
}
}
drv_lcd_clear();
struct drv_lcd_coordinate coord;
drv_lcd_coordinate_create(&coord, -40, 125);
drv_lcd_draw_coordinate_with_color(&coord, 18,10, 100, 100, RED);
while (1) {
uint16_t adc_value = drv_adc_read(0);
if(++tick >= 10)
{
tick = 0;
if(drv_nst112_read_temp(&temp))
{
int num = snprintf(str_buf, 31, "T%.02f,A%d,D%d \n", temp, adc_value, duty);
led_process(&temp);
uart_puts(0, str_buf);
str_buf[num - 1] = ' ';
drv_lcd_string(10,113,0,str_buf);
if(!keep)
{
temp_buf_write((int8_t)temp);
}
drv_lcd_draw_coordinate_point(&coord, temp_buf, temp_buf_cnt);
}
}
key_active = key_process(adc_value, key_active, &duty);
if(key_active == KEY_UP_RELEASE || key_active == KEY_DOWN_RELEASE)
{
key_active = KEY_NULL;
drv_pwm_set(2, 100, duty);
}
if(key_active == KEY_OK_RELEASE)
{
key_active = KEY_NULL;
keep = !keep;
}
_delay_ms(100);
}
}
其中主要的函数及逻辑有:
- sysclk_init():进行时钟初始化,里面实现了采用外部24MHz晶振和内置24MHz高速晶振两种系统时钟。
- board_init():硬件外设初始化,包括led、uart、lcd、pwm、adc。
- i2c_send_bytes(0, 0, &tmp, 1):其中tmp=0x06,参考nst112手册,这是复位内部寄存器操作,具体查看手册《3.4.3.3 General Call》
- mask = i2c_device_check(0, 0x48, 0x4C):实现I2C设备检测,检测范围是0x38到0x4C,返回检测到的设备掩码(哪几个设备有应答),具体可以查看源码实现
- drv_nst112_init(0x48+i):初始化相应地址的温度传感器
- drv_lcd_coordinate_create(&coord, -15, 125):创建一个y坐标是-15到125的一个坐标系
- drv_lcd_draw_coordinate_with_color(&coord, 18,10, 100, 100, RED):在屏幕(18,10)处绘制这个坐标系,大小是100x100,使用红色绘制
- drv_adc_read(0):读取通道0的ADC值,通道定义可以查看源码
- drv_nst112_read_temp(&temp):读取温度数据
- led_process(&temp):根据温度数据点亮不同的LED灯
- temp_buf_write((int8_t)temp):保存温度到缓存中
- drv_lcd_draw_coordinate_point(&coord, temp_buf, temp_buf_cnt):绘制保存的温度曲线
- key_process(adc_value, key_active, &duty):根据按键更新pwm占空比
- drv_pwm_set(2, 100, duty):更新PWM占用比
主函数介绍完毕。
其他的代码就直接看源码吧,源码里面有较详细的中文注释。
功能展示
- 下图标出了按键的功能,当前是绿灯,即温度大于20度小于50度。
屏幕的内容中T表示温度,A表示ADC读到的值,D表示PWM的占空比,1000表示10%。
- 下图是一个温度变化曲线:
- 下图是当温度高于50度后LED灯的变化:
其他说明:UP键是用来增加占空比的,按一次增加10%,DOWN键是减少占空比的,一次减少10%,OK键是用来截图的,按下后温度曲线就会保持住,但是没有存储下来,再按一次后就会接着采集温度了。
心得体会
通过本次活动,了解了AVR64DD32单片机的使用,包括时钟配置,GPIO、I2C、SPI、PWM、ADC等的使用以及LCD屏、NST112温度传感器,相对往期来说,写的代码也是最多的,所有驱动都是自己写的。
对比ARM单片机,AVR单片机还是要简单很多的,做一些简单功能的产品还是可以拿来用的,不过这款单片机没有看到对arduino的支持,这个比较遗憾。
最后希望编辑区支持markdown语法,方便绘图等操作,如果已支持,希望有个帮助来指导如果使用此功能。