功能:使用数码管显示温湿度并实时检测环境温度
1> 显示温度的格式 : 22.5c(目前无法显示0度以下的温度)
2> 显示湿度的格式 : 45.6H / 45.6r
3> 每隔5s钟刷新一次温湿度的显示(先显示5s的温度,在显示5s湿度)(逻辑的实现)
4> KEY1按下,立即测量温度并更新显示
5> KEY2按下,立即测量湿度并更新显示
6> 实现温湿度阈值报警的功能,并且控制风扇调速。
7> 用于检查错误;显示报警。
温度检测流程:温度检测–>设置阈值–>超过阈值导致led灯亮、蜂鸣器报警。
湿度检测流程:湿度检测–>设置阈值–>超过阈值导致led灯亮、开启风扇。
更新数据:
按下key1更新温度
按下key2更新湿度
本次项目采用的是STM32单片机。使用的温湿度传感器芯片是si7006。
我在这里就不一一讲述了,每种单片机的引脚功能各不相同。
我在这个项目中,将各器件进行了初始化我在这里就不一一讲述了,每种单片机的引脚功能各不相同。
初始化了led1,led2灯作为报警指示灯。
初始化风扇、蜂鸣器用于报警后的处理。
初始化数字显像管作为显示温度数值的模块。
4.初始化温湿度传感器用来收集环境温度和数值。
函数流程设计思路:
主函数:
第一步:先调用传感器采集数据,作为第一次采集的初试数据,每隔5秒,重新采集数据
第二步:将采集来的数据显示在显像管上。
第三步:在自动更新的过程中,设计了按键中断,按下按键可以触发中断,主动更新一次数据并继续显示数据的循环。
第四步:设置报警阈值,当数据超过阈值时触发报警机制,激活对应设备及led灯,当数值低于阈值时,关闭对应设备,熄灭led灯。
void delay_ms(unsigned int ms);
void temp_check(unsigned short num){
if(num>280){
//led1高电平,蜂鸣器高电平
hal_gpio_write(GPIOE, GPIO_PIN_10, GPIO_SET);
hal_gpio_write(GPIOB,GPIO_PIN_6,GPIO_SET);
}else if(num <=280){
//led1低电平,蜂鸣器低电平
hal_gpio_write(GPIOE, GPIO_PIN_10, GPIO_RESET);
hal_gpio_write(GPIOB,GPIO_PIN_6,GPIO_RESET);
}
}
void hum_check(unsigned short num){
if(num>700){
//led3高电平,风扇高电平
hal_gpio_write(GPIOE, GPIO_PIN_8, GPIO_SET);
hal_gpio_write(GPIOE, GPIO_PIN_9, GPIO_SET);
}else if(num <=700){
//led3低电平,风扇低电平
hal_gpio_write(GPIOE,GPIO_PIN_8, GPIO_RESET);
hal_gpio_write(GPIOE, GPIO_PIN_9, GPIO_RESET);
}
}
//温度和湿度显示
void temp_show(unsigned short temp_value,unsigned char* tem){
//显示温度
for (j = 0 ; j < 725 ; j++)
for (i = 0; i < 4; i++) { // 选择位
//触发中断更新温度数据
if(measure_again == 2){
hum_value = si7006_read_hum_data(SI7006_SLAVE, MEASURE_HUM_CMD);
hum_value = (125 * hum_value / 65536 - 6) * 10;
//终端显示
hum_check(hum_value);
printf("hum update!");
printf("hum value = %d.%d\n", hum_value / 10, hum_value % 10);
num(hum_value,hum);
measure_again=0;
hum_show(hum_value,hum);
}else if(measure_again==1){
temp_value = si7006_read_temp_data(SI7006_SLAVE, MEASURE_TEMP_CMD);
temp_value = (175.72 * temp_value / 65536 - 46.85) * 10;
temp_check(temp_value);
//终端显示
printf("temp update!");
printf("temp value = %d.%d\n", temp_value / 10, temp_value % 10);
num(temp_value,tem);
measure_again=0;
temp_show(temp_value,tem);
}
SPI_write(0x80 >> i); // 依次发送数码管显示的位
SPI_write(tem[i]); // 依次发送数码管的段,让数码管显示不同的数字
NSS_OUTPUT_L();
delay_ms(1);
NSS_OUTPUT_H();
// delay_ms(500); // 不可以有延时
}
}
void hum_show(unsigned short hum_value,unsigned char *hum){
for (j = 0; j < 725; j++) {
for (i = 0; i < 4; i++) { // 选择位
//触发中断更新温度数据
if(measure_again == 2){
hum_value = si7006_read_hum_data(SI7006_SLAVE, MEASURE_HUM_CMD);
hum_value = (125 * hum_value / 65536 - 6) * 10;
//终端显示
hum_check(hum_value);
printf("hum update!");
printf("hum value = %d.%d\n", hum_value / 10, hum_value % 10);
num(hum_value,hum);
measure_again=0;
hum_show(hum_value,hum);
}else if(measure_again==1){
temp_value = si7006_read_temp_data(SI7006_SLAVE, MEASURE_TEMP_CMD);
temp_value = (175.72 * temp_value / 65536 - 46.85) * 10;
//终端显示
temp_check(temp_value);
printf("temp update!");
printf("temp value = %d.%d\n", temp_value / 10, temp_value % 10);
num(temp_value,tem);
measure_again=0;
temp_show(temp_value,tem);
}
SPI_write(0x80 >> i); // 依次发送数码管显示的位
SPI_write(hum[i]); // 依次发送数码管的段,让数码管显示不同的数字
NSS_OUTPUT_L();
delay_ms(1);
NSS_OUTPUT_H();
// delay_ms(500); // 不可以有延时
}
}
}
//将读取到的数据转换成显像管需要的十六进制数据
unsigned char rnum(unsigned short t)
{
switch (t) {
case 0:
return 0xFC;
break;
case 1:
return 0x60;
break;
case 2:
return 0xDA;
break;
case 3:
return 0xF2;
break;
case 4:
return 0x66;
break;
case 5:
return 0xB6;
break;
case 6:
return 0xBE;
break;
case 7:
return 0xE0;
break;
case 8:
return 0xFE;
break;
case 9:
return 0xF6;
break;
}
}
//转换数据函数
void num(unsigned short a, unsigned char* ret)
{
short t;
int s = a;
t = s / 100; // 10位
ret[0] = rnum(t);
t = s % 10; //个位
ret[2] = rnum(t);
s /= 10;
t = s % 10;
ret[1] = rnum(t) | 0x1;
}
extern char buffer[LEN];
int main()
{
//设置变量用于接收温度和湿度
si7006_init();
//驱动初始化
hal_led_init(); //初始化指示灯
//串口的初始化
hal_uart4_init();
//中断初始化
// KEY1
hal_gpio_IT_init(GPIOF, GPIO_PIN_9);
hal_exti_IT_init(GPIO_PIN_9, GPIOF_EXTI, FALLING_EDGE);
hal_gic_IT_init(99, 1);
// KEY2
hal_gpio_IT_init(GPIOF, GPIO_PIN_7);
hal_exti_IT_init(GPIO_PIN_7, GPIOF_EXTI, FALLING_EDGE);
hal_gic_IT_init(97, 1);
//定时器初始化
hal_tim5_IT_init();
//数字管显示初始化
SPI_init();
while (1) {
//显示温湿度信息
//接收初试温湿度信息以及转化
hum_value = si7006_read_hum_data(SI7006_SLAVE, MEASURE_HUM_CMD);
temp_value = si7006_read_temp_data(SI7006_SLAVE, MEASURE_TEMP_CMD);
hum_value = (125 * hum_value / 65536 - 6) * 10;
temp_value = (175.72 * temp_value / 65536 - 46.85) * 10;
//终端显示
hum_check(hum_value);
temp_check(temp_value);
printf("hum value = %d.%d\n", hum_value / 10, hum_value % 10);
printf("temp value = %d.%d\n", temp_value / 10, temp_value % 10);
num(temp_value,tem);
num(hum_value,hum);
//将信息转换成字符型
temp_show(temp_value,tem);
//显示湿度
hum_show(hum_value,hum);
}
return 0;
}
延时函数:
延时函数的作用主要是用来作为计时程序使用。相当于c语言中的sleep函数,但是因为我所用的是裸机设备,所以需要自己设计延时程序。
注:如果不用延时程序来实现每个五秒重新采集数据的话,则需要使用单片机的计时器功能来进行延时功能。计时器需要搭配中断处理程序来实现数据更新。
void delay_ms(unsigned int ms)
{
int i, j;
for (i = 0; i < ms; i++)
for (j = 0; j < 1800; j++)
;
}
中断处理函数:
将中断后处理方式进行标志量赋值:将对应标志位进行更改,达到一种信号传导作用。
部分代码展示:
extern int measure_again;
void do_irq(void)
{ // 1. 获取当前处理的中断的中断号 GICC_IAR[9:0]
int irq_num;
irq_num = GICC->IAR & 0x3FF;
switch (irq_num)
{
case 82: // TIM5计时器
// 2. 调用82号中断的处理函数
printf("TIM5 1s timer interrupt ID = %d\n", irq_num);
// 3. 清除TIM5层的中断挂起标志位
hal_tim5_clear_IT();
// 4. 清除GICD层的中断挂起标志位 GICD_ICPENDR3[3]
hal_gicd_clear_IT(irq_num);
break;
case 97: // KEY2
// 2. 调用97号中断的处理函数
measure_again = 2;
// 3. 清除EXTI层的中断挂起标志位 EXTI_FPR1[9]
hal_exti_clear_IT(GPIO_PIN_7, FALLING_EDGE);
// 4. 清除GICD层的中断挂起标志位 GICD_ICPENDR3[3]
hal_gicd_clear_IT(irq_num);
break;
case 99: // 99 号中断处理程序 KEY1
// 2. 调用99号中断的处理函数
measure_again = 1;
// 3. 清除EXTI层的中断挂起标志位 EXTI_FPR1[9]
hal_exti_clear_IT(GPIO_PIN_9, FALLING_EDGE);
// 4. 清除GICD层的中断挂起标志位 GICD_ICPENDR3[3]
hal_gicd_clear_IT(irq_num);
break;
default:
break;
}
// 5. 清除GICC层的中断号
GICC->EOIR = irq_num;
}