RELAY_Init();//继电器初始化

时间: 2025-03-30 20:10:02 浏览: 77
### 继电器初始化函数的功能与用法 在嵌入式开发中,`Relay_Init()` 函数通常用于完成继电器硬件接口的初始化工作。此函数的主要目的是设置微控制器的相关寄存器,以便能够通过指定的端口和引脚来控制继电器的状态。 #### 初始化函数的作用 继电器初始化函数的核心功能是对GPIO(通用输入/输出)端口进行配置,使其可以作为输出模式运行,并设定默认状态。以下是常见的实现逻辑: 1. **配置GPIO端口的工作模式** 将负责驱动继电器的GPIO引脚设置为输出模式。这一步通常是通过修改微控制器内部的GPIO配置寄存器完成的[^1]。 2. **设置初始状态** 在某些情况下,为了防止意外触发设备,在初始化阶段会将继电器设置到安全的默认状态(例如关闭)。这种操作可以通过调用 `GPIO_SetBits()` 或类似的API实现[^2]。 3. **使能外设时钟** 如果目标MCU架构需要手动开启特定外设模块的电源供应,则还需要激活对应的时钟信号源。这是确保所有后续指令正常工作的前提条件之一[^3]。 下面展示了一个可能版本的继电器初始化代码片段: ```c void Relay_Init(void){ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 启动GPIOA时钟 GPIO_InitTypeDef GPIO_InitStructure; /* 配置GPIOA Pin_x 为推挽输出 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_x; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); } ``` 上述例子假设使用的是STM32系列芯片及其标准库编程环境。其中包含了启动相应GPIO组的时钟资源以及定义具体的针脚行为两大部分内容。 值得注意的是实际项目里可能会依据具体需求调整参数或者增加额外处理流程比如错误检测机制等等。 ### 实际应用中的注意事项 当把这样的基础构建块融入更大规模的应用程序当中时,请记得考虑如下几点事项: - 确认所选用的具体型号支持计划采用的操作方式; - 查阅数据手册确认电气特性是否匹配负载要求; - 对时间敏感型任务安排合理的调度策略避免冲突干扰;
阅读全文

相关推荐

#include <reg52.h> //调用单片机头文件 #define uchar unsigned char //无符号字符型 宏定义 变量范围0~255 #define uint unsigned int //无符号整型 宏定义 变量范围0~65535 //数码管段选定义 0 1 2 3 4 5 6 7 8 9 uchar code smg_du[]={0x14,0x77,0x4c,0x45,0x27,0x85,0x84,0x57,0x04,0x05}; //断码 uchar dis_smg[4] = {0xff,0xff,0xff,0xff}; //数码管显示数组的缓冲区 sbit dq = P1^6; //18b20 IO口的定义 sbit beep = P3^3; //蜂鸣器IO口定义 sbit key1 = P3^5; //按键IO口定义 sbit key2 = P3^6; //按键IO口定义 sbit key3 = P3^7; //按键IO口定义 uchar flag_lj_en; //按键连加变量 uint temperature ; //温度变量 bit flag_300ms ; //300毫秒的变量 uchar menu_1; //设置不同报警参数的变量 uint t_high = 350,t_low = 100; //温度上下限报警值 // 全局变量定义 uint temperature; // 当前温度 uint temp_buffer[10]; // 温度缓冲区 uchar temp_count = 0; // 温度计数器 bit flag_stable_check = 0; // 稳定检查标志位 uint temperature_c; // 当前温度(摄氏度) uint temperature_f; // 当前温度(华氏度) uchar unit_flag = 0; // 温度单位标志位 0: 摄氏度, 1: 华氏度 //数码管位选定义 sbit smg_we1 = P2^0; //数码管位选IO口定义 sbit smg_we2 = P2^2; //数码管位选IO口定义 sbit smg_we3 = P2^4; //数码管位选IO口定义 sbit smg_we4 = P2^6; //数码管位选IO口定义 sbit relay1 = P1^5; //温度下限继电器IO口定义 sbit relay2 = P1^3; //温度上限继电器IO口定义 uchar flag_en = 1; /***********************数码位选函数*****************************/ void smg_we_switch(uchar i) { switch(i) { case 0: smg_we1 = 0; smg_we2 = 1; smg_we3 = 1; smg_we4 = 1; break; case 1: smg_we1 = 1; smg_we2 = 0; smg_we3 = 1; smg_we4 = 1; break; case 2: smg_we1 = 1; smg_we2 = 1; smg_we3 = 0; smg_we4 = 1; break; case 3: smg_we1 = 1; smg_we2 = 1; smg_we3 = 1; smg_we4 = 0; break; } } /***********************1ms延时函数*****************************/ void delay_1ms(uint q) { uint i,j; for(i=0;i<q;i++) for(j=0;j<120;j++); } /***********************小延时函数*****************************/ void delay_uint(uint q) { while(q--); } /***********************数码显示函数*****************************/ void display() { static uchar i; i++; if(i >= 4) i = 0; P0 = 0xff; //消隐 smg_we_switch(i); //位选 P0 = dis_smg[i]; //段选 } /***********************18b20初始化函数*****************************/ void init_18b20() { bit q; dq = 1; //把总线拿高 delay_uint(1); dq = 0; //给复位脉冲 delay_uint(80); dq = 1; //把总线拿高 等待 delay_uint(10); q = dq; //读取18b20初始化信号 delay_uint(20); dq = 1; //把总线拿高 释放总线 } /*************写18b20内的数据***************/ void write_18b20(uchar dat) { uchar i; for(i=0;i<8;i++) { //写数据是低位开始 dq = 0; //把总线拿低写时间隙开始 dq = dat & 0x01; //向18b20总线写数据了 delay_uint(5); // 60us dq = 1; //释放总线 dat >>= 1; } } /*************读取18b20内的数据***************/ uchar read_18b20() { uchar i,value; for(i=0;i<8;i++) { dq = 0; //把总线拿低读时间隙开始 value >>= 1; //读数据是低位开始 dq = 1; //释放总线 if(dq == 1) //开始读写数据 value |= 0x80; delay_uint(5); //60us 读一个时间隙最少要保持60us的时间 } return value; //返回数据 } /*************读取温度的值 读出来的是小数***************/ uint read_temp() { uint value; uchar low; //在读取温度的时候如果中断的太频繁了,就应该把中断给关了,否则会影响到18b20的时序 init_18b20(); //初始化18b20 write_18b20(0xcc); //跳过64位ROM write_18b20(0x44); //启动一次温度转换命令 delay_uint(50); //500us EA = 0; init_18b20(); //初始化18b20 write_18b20(0xcc); //跳过64位ROM write_18b20(0xbe); //发出读取暂存器命令 low = read_18b20(); //读温度低字节 value = read_18b20(); //读温度高字节 EA = 1; value <<= 8; //把温度的高位左移8位 value |= low; //把读出的温度低位放到value的低八位中 value *= 0.625; //转换到温度值 小数 return value; //返回读出的温度 } /*************定时器0初始化程序***************/ void time_init() { EA = 1; //开总中断 TMOD = 0X01; //定时器0、定时器1工作方式1 ET0 = 1; //开定时器0中断 TR0 = 1; //允许定时器0定时 TH0 = 0xf8; TL0 = 0x30; //2ms } /********************独立按键程序*****************/ uchar key_can; // 按键值 uchar key_delay; // 按键延时计数器 void key() // 独立按键程序 { key_can = 0; // 按键值还原成0 if(key1 == 0 || key2 == 0 || key3 == 0) // 有按键按下 { delay_1ms(10); // 按键延时消抖动 if(key1 == 0) // 确认是按键按下 key_can = 1; // 得到按键值 if(key2 == 0) // 确认是按键按下 key_can = 2; // 得到按键值 if(key3 == 0) // 确认是按键按下 key_can = 3; // 得到按键值 if(++key_delay >= 5) // 连续按键超过5次触发连加/连减 { flag_lj_en = 1; // 开启连加/连减模式 } } else { flag_lj_en = 0; // 关闭连加/连减模式 key_delay = 0; // 清零延时计数器 } } /****************按键处理数码管显示函数***************/ void key_with() { if(key_can == 1) //设置键 { menu_1 ++; if(menu_1 >= 3) { menu_1 = 0; //menu_1 = 0 退出设置了, } } if(menu_1 == 1) //设置温度上限报警值 { if(key_can == 2) //加键 { if(flag_lj_en <= 3) t_high ++ ; //按键按下未松开加1 加三次 else t_high += 10; //按键按下未松开加三次后加10 if(t_high > 999) t_high = 999; } if(key_can == 3) //减键 { if(flag_lj_en <= 3) t_high -- ; //按键按下未松开减1 减三次 else t_high -= 10; //按键按下未松开减三次后减10 if(t_high <= t_low) t_high = t_low + 1; //限制温度上限不能低于温度下限 } dis_smg[0] = smg_du[t_high % 10]; //取小数显示 dis_smg[1] = smg_du[t_high / 10 % 10] & 0xfb; //取个位显示 dis_smg[2] = smg_du[t_high / 100 % 10] ; //取十位显示 dis_smg[3] = 0x26; //显示H } if(menu_1 == 2) //设置温度下限报警值 { if(key_can == 2) //加键 { if(flag_lj_en <= 3) t_low ++ ; //按键按下未松开加1 加三次 else t_low += 10; //按键按下未松开加三次后加10 if(t_low >= t_high) t_low = t_high - 1; //限制温度下限不能高于温度上限 } if(key_can == 3) //减键 { if(flag_lj_en <= 3) t_low -- ; //按键按下未松开减1 减三次 else t_low -= 10; //按键按下未松开减三次后减10 if(t_low <= 10) t_low = 10; } dis_smg[0] = smg_du[t_low % 10]; //取小数显示 dis_smg[1] = smg_du[t_low / 10 % 10] & 0xfb; //取个位显示 dis_smg[2] = smg_du[t_low / 100 % 10] ; //取十位显示 dis_smg[3] = 0xBC; //显示L } delay_1ms(400); } /****************报警函数***************/ void clock_h_l() { if((temperature <= t_low) || (temperature >= t_high)) //温度小于等于下限 或者 温度大于等于上限 { if(flag_en == 1) beep = ~beep; //蜂鸣器报警 if(temperature <= t_low) relay1 = 0; //打开继电器 if(temperature >= t_high) relay2 = 0; //打开继电器 } else { beep = 1; //取消报警 relay1 = 1; //关闭继电器 relay2 = 1; //关闭继电器 flag_en = 1; } } /****************读取温度并存入缓冲区***************/ void read_temp_into_buffer() { temperature = read_temp(); // 读取当前温度 temp_buffer[temp_count++] = temperature; // 存入缓冲区 } /****************检查温度稳定性***************/ void check_temperature_stability() { uint max_temp = 0, min_temp = 999; uint i,diff; // 查找最大值和最小值 for(i = 0; i < 5; i++) // 遍历5个温度值 { if(temp_buffer[i] > max_temp) max_temp = temp_buffer[i]; if(temp_buffer[i] < min_temp) min_temp = temp_buffer[i]; } // 计算差值 diff = max_temp - min_temp; if(diff > 18) // 差值大于0.5 (因为温度单位是0.625倍的实际温度) { flag_stable_check = 1; // 标记为不稳定,继续检测 } else { flag_stable_check = 0; // 标记为稳定,进入报警判断 clock_h_l(); // 报警函数 } } /****************更新温度显示***************/ void update_temperature_display() { if(unit_flag == 0) // 显示摄氏度 { dis_smg[0] = smg_du[temperature_c % 100]; // 小数部分 dis_smg[1] = smg_du[temperature_c / 100 % 10] & 0xfb; // 个位 dis_smg[2] = smg_du[temperature_c / 1000 % 10]; // 十位 dis_smg[3] = 0xFF; // 不显示符号 } else // 显示华氏度 { dis_smg[0] = smg_du[temperature_f % 100]; // 小数部分 dis_smg[1] = smg_du[temperature_f / 100 % 10] & 0xfb; // 个位 dis_smg[2] = smg_du[temperature_f / 1000 % 10]; // 十位 dis_smg[3] = smg_du[temperature_f / 10000 % 10]; } } /****************主函数***************/ void main() { beep = 0; // 开机叫一声 delay_1ms(150); P0 = P1 = P2 = P3 = 0xff; // 所有单片机IO口输出高电平 time_init(); // 初始化定时器 while(1) { key(); // 按键程序 if(key_can > 0) { key_with(); // 设置温度上下限值 if(menu_1 == 0) { if(key_can == 3) { flag_en = 0; // 手动取消报警 beep = 1; // 关闭蜂鸣器 } } } if(flag_300ms == 1) // 300ms 处理一次温度程序 { flag_300ms = 0; read_temp_into_buffer(); // 将温度读入缓冲区 if(temp_count >= 5) // 如果已经收集了10个温度值 { check_temperature_stability(); // 检查温度稳定性 temp_count = 0; // 重置计数器 } // 实时更新数码管显示 if(menu_1 == 0) { if(key_can == 3) // 按键3用于切换温度单位 { unit_flag = !unit_flag; // 切换标志位 } temperature_c = (uint)(read_temp()*10); // 读取摄氏温度 temperature_f = (temperature_c * 90 / 50) + 3200; // 转换为华氏温度 update_temperature_display(); // 更新显示 } } delay_1ms(1); } } /*************定时器0中断服务程序***************/ void time0_int() interrupt 1 { static uchar value; //定时2ms中断一次 TH0 = 0xf8; TL0 = 0x30; //2ms display(); //数码管显示函数 value++; if(value >= 150) { value = 0; flag_300ms = 1; //定时产生一个300毫秒的变量 } }

#include <reg52.h> //调用单片机头文件 #include <math.h> #define uchar unsigned char //无符号字符型 宏定义 变量范围0~255 #define uint unsigned int //无符号整型 宏定义 变量范围0~65535 //数码管段选定义 0 1 2 3 4 5 6 7 8 9 uchar code smg_du[]={0x14,0x77,0x4c,0x45,0x27,0x85,0x84,0x57,0x04,0x05}; //断码 uchar dis_smg[4] = {0xff,0xff,0xff,0xff}; //数码管显示数组的缓冲区 sbit dq = P1^6; //18b20 IO口的定义 sbit beep = P3^3; //蜂鸣器IO口定义 sbit key1 = P3^5; //按键IO口定义 sbit key2 = P3^6; //按键IO口定义 sbit key3 = P3^7; //按键IO口定义 uchar flag_lj_en; //按键连加变量 uint temperature ; //温度变量 bit flag_300ms ; //300毫秒的变量 uchar menu_1; //设置不同报警参数的变量 uint t_high = 350,t_low = 100; //温度上下限报警值 // 全局变量定义 uint temperature; // 当前温度 uint temp_buffer[4][5]; // 四组温度缓冲区,每组5个温度值 uchar temp_count = 0; // 温度计数器 uchar group_count = 0; // 组计数器 uint avg_temps[4]; // 每组的平均值 bit flag_stable_check = 0; // 稳定检查标志位 uint temperature_c; // 当前温度(摄氏度) uint temperature_f; // 当前温度(华氏度) uchar unit_flag = 0; // 温度单位标志位 0: 摄氏度, 1: 华氏度 //数码管位选定义 sbit smg_we1 = P2^0; //数码管位选IO口定义 sbit smg_we2 = P2^2; //数码管位选IO口定义 sbit smg_we3 = P2^4; //数码管位选IO口定义 sbit smg_we4 = P2^6; //数码管位选IO口定义 sbit relay1 = P1^5; //温度下限继电器IO口定义 sbit relay2 = P1^3; //温度上限继电器IO口定义 uchar flag_en = 1; /***********************数码位选函数*****************************/ void smg_we_switch(uchar i) { switch(i) { case 0: smg_we1 = 0; smg_we2 = 1; smg_we3 = 1; smg_we4 = 1; break; case 1: smg_we1 = 1; smg_we2 = 0; smg_we3 = 1; smg_we4 = 1; break; case 2: smg_we1 = 1; smg_we2 = 1; smg_we3 = 0; smg_we4 = 1; break; case 3: smg_we1 = 1; smg_we2 = 1; smg_we3 = 1; smg_we4 = 0; break; } } /***********************1ms延时函数*****************************/ void delay_1ms(uint q) { uint i,j; for(i=0;i<q;i++) for(j=0;j<120;j++); } /***********************小延时函数*****************************/ void delay_uint(uint q) { while(q--); } /***********************数码显示函数*****************************/ void display() { static uchar i; i++; if(i >= 4) i = 0; P0 = 0xff; //消隐 smg_we_switch(i); //位选 P0 = dis_smg[i]; //段选 } /***********************18b20初始化函数*****************************/ void init_18b20() { bit q; dq = 1; //把总线拿高 delay_uint(1); dq = 0; //给复位脉冲 delay_uint(80); dq = 1; //把总线拿高 等待 delay_uint(10); q = dq; //读取18b20初始化信号 delay_uint(20); dq = 1; //把总线拿高 释放总线 } /*************写18b20内的数据***************/ void write_18b20(uchar dat) { uchar i; for(i=0;i<8;i++) { //写数据是低位开始 dq = 0; //把总线拿低写时间隙开始 dq = dat & 0x01; //向18b20总线写数据了 delay_uint(5); // 60us dq = 1; //释放总线 dat >>= 1; } } /*************读取18b20内的数据***************/ uchar read_18b20() { uchar i,value; for(i=0;i<8;i++) { dq = 0; //把总线拿低读时间隙开始 value >>= 1; //读数据是低位开始 dq = 1; //释放总线 if(dq == 1) //开始读写数据 value |= 0x80; delay_uint(5); //60us 读一个时间隙最少要保持60us的时间 } return value; //返回数据 } /*************读取温度的值 读出来的是小数***************/ uint read_temp() { uint value; uchar low; //在读取温度的时候如果中断的太频繁了,就应该把中断给关了,否则会影响到18b20的时序 init_18b20(); //初始化18b20 write_18b20(0xcc); //跳过64位ROM write_18b20(0x44); //启动一次温度转换命令 delay_uint(50); //500us EA = 0; init_18b20(); //初始化18b20 write_18b20(0xcc); //跳过64位ROM write_18b20(0xbe); //发出读取暂存器命令 low = read_18b20(); //读温度低字节 value = read_18b20(); //读温度高字节 EA = 1; value <<= 8; //把温度的高位左移8位 value |= low; //把读出的温度低位放到value的低八位中 value *= 0.625; //转换到温度值 小数 return value; //返回读出的温度 } /*************定时器0初始化程序***************/ void time_init() { EA = 1; //开总中断 TMOD = 0X01; //定时器0、定时器1工作方式1 ET0 = 1; //开定时器0中断 TR0 = 1; //允许定时器0定时 TH0 = 0xf8; TL0 = 0x30; //2ms } /********************独立按键程序*****************/ uchar key_can; // 按键值 uchar key_delay; // 按键延时计数器 void key() // 独立按键程序 { key_can = 0; // 按键值还原成0 if(key1 == 0 || key2 == 0 || key3 == 0) // 有按键按下 { delay_1ms(10); // 按键延时消抖动 if(key1 == 0) // 确认是按键按下 key_can = 1; // 得到按键值 if(key2 == 0) // 确认是按键按下 key_can = 2; // 得到按键值 if(key3 == 0) // 确认是按键按下 key_can = 3; // 得到按键值 if(++key_delay >= 5) // 连续按键超过5次触发连加/连减 { flag_lj_en = 1; // 开启连加/连减模式 } } else { flag_lj_en = 0; // 关闭连加/连减模式 key_delay = 0; // 清零延时计数器 } } /****************按键处理数码管显示函数***************/ void key_with() { if(key_can == 1) //设置键 { menu_1 ++; if(menu_1 >= 3) { menu_1 = 0; //menu_1 = 0 退出设置了, } } if(menu_1 == 1) //设置温度上限报警值 { if(key_can == 2) //加键 { if(flag_lj_en <= 3) t_high ++ ; //按键按下未松开加1 加三次 else t_high += 10; //按键按下未松开加三次后加10 if(t_high > 999) t_high = 999; } if(key_can == 3) //减键 { if(flag_lj_en <= 3) t_high -- ; //按键按下未松开减1 减三次 else t_high -= 10; //按键按下未松开减三次后减10 if(t_high <= t_low) t_high = t_low + 1; //限制温度上限不能低于温度下限 } dis_smg[0] = smg_du[t_high % 10]; //取小数显示 dis_smg[1] = smg_du[t_high / 10 % 10] & 0xfb; //取个位显示 dis_smg[2] = smg_du[t_high / 100 % 10] ; //取十位显示 dis_smg[3] = 0x26; //显示H } if(menu_1 == 2) //设置温度下限报警值 { if(key_can == 2) //加键 { if(flag_lj_en <= 3) t_low ++ ; //按键按下未松开加1 加三次 else t_low += 10; //按键按下未松开加三次后加10 if(t_low >= t_high) t_low = t_high - 1; //限制温度下限不能高于温度上限 } if(key_can == 3) //减键 { if(flag_lj_en <= 3) t_low -- ; //按键按下未松开减1 减三次 else t_low -= 10; //按键按下未松开减三次后减10 if(t_low <= 10) t_low = 10; } dis_smg[0] = smg_du[t_low % 10]; //取小数显示 dis_smg[1] = smg_du[t_low / 10 % 10] & 0xfb; //取个位显示 dis_smg[2] = smg_du[t_low / 100 % 10] ; //取十位显示 dis_smg[3] = 0xBC; //显示L } delay_1ms(400); } /****************报警函数***************/ void clock_h_l() { if((temperature <= t_low) || (temperature >= t_high)) //温度小于等于下限 或者 温度大于等于上限 { if(flag_en == 1) beep = ~beep; //蜂鸣器报警 if(temperature <= t_low) relay1 = 0; //打开继电器 if(temperature >= t_high) relay2 = 0; //打开继电器 } else { beep = 1; //取消报警 relay1 = 1; //关闭继电器 relay2 = 1; //关闭继电器 flag_en = 1; } } /****************读取温度并存入缓冲区***************/ void read_temp_into_buffer() { temperature = read_temp(); // 读取当前温度 temp_buffer[group_count][temp_count++] = temperature; // 存入缓冲区 } // 计算每组的平均值 void calculate_average_temperatures() { uint i, j, sum; for (i = 0; i < 4; i++) { sum = 0; for (j = 0; j < 5; j++) { sum += temp_buffer[i][j]; } avg_temps[i] = sum / 5; // 计算每组的平均值 } } /****************检查温度稳定性***************/ void check_temperature_stability() { uint max_temp = 0, min_temp = 999; uint i, diff; // 查找最大值和最小值 for(i = 0; i < 4; i++) // 遍历四组平均值 { if(avg_temps[i] > max_temp) max_temp = avg_temps[i]; if(avg_temps[i] < min_temp) min_temp = avg_temps[i]; } // 计算差值 diff = max_temp - min_temp; if(diff > 6) // 差值大于 { flag_stable_check = 1; // 标记为不稳定,继续检测 } else { flag_stable_check = 0; // 标记为稳定,进入报警判断 clock_h_l(); // 报警函数 } } /****************更新温度显示***************/ void update_temperature_display() { if(unit_flag == 0) // 显示摄氏度 { dis_smg[0] = smg_du[temperature_c % 10]; // 小数部分 dis_smg[1] = smg_du[temperature_c / 10 % 10] & 0xfb; // 个位 dis_smg[2] = smg_du[temperature_c / 100 % 10]; // 十位 dis_smg[3] = 0xFF; // 不显示符号 } else // 显示华氏度 { dis_smg[0] = smg_du[temperature_f % 10]; // 小数部分 dis_smg[1] = smg_du[temperature_f / 10 % 10] & 0xfb; // 个位 dis_smg[2] = smg_du[temperature_f / 100 % 10]; // 十位 dis_smg[3] = smg_du[temperature_f / 1000 % 10]; } } /****************主函数***************/ void main() { beep = 0; // 开机叫一声 delay_1ms(150); P0 = P1 = P2 = P3 = 0xff; // 所有单片机IO口输出高电平 time_init(); // 初始化定时器 while(1) { key(); // 按键程序 if(key_can > 0) { key_with(); // 设置温度上下限值 if(menu_1 == 0) { if(key_can == 3) { flag_en = 0; // 手动取消报警 beep = 1; // 关闭蜂鸣器 } } } if(flag_300ms == 1) // 300ms 处理一次温度程序 { flag_300ms = 0; if (temp_count < 5) { // 如果当前组未满 read_temp_into_buffer(); // 将温度读入缓冲区 } else { // 当前组已满 if (group_count < 3) { // 如果还未收集完四组 group_count++; // 切换到下一组 temp_count = 0; // 重置计数器 } else { // 已经收集完四组 calculate_average_temperatures(); // 计算每组的平均值 check_temperature_stability(); // 检查温度稳定性 group_count = 0; // 重置组计数器 temp_count = 0; // 重置计数器 } } // 实时更新数码管显示 if(menu_1 == 0) { uint tem; if(key_can == 3) // 按键3用于切换温度单位 { unit_flag = !unit_flag; // 切换标志位 } temperature_c = read_temp(); // 读取摄氏温度 tem = (temperature_c * 18) + 3200; temperature_f = tem / 10; // 转换为华氏温度 update_temperature_display(); // 更新显示 } } delay_1ms(1); } } /*************定时器0中断服务程序***************/ void time0_int() interrupt 1 { static uchar value; //定时2ms中断一次 TH0 = 0xf8; TL0 = 0x30; //2ms display(); //数码管显示函数 value++; if(value >= 150) { value = 0; flag_300ms = 1; //定时产生一个300毫秒的变量 } } 为什么该程序无法进行报警程序

#include <REGX52.H> #include "delay.h" #include "LCD1602.h" #include "DS18B02.h" #include "key.h" #include "Buzzer.h" sbit Relay=P1^4;//定义继电器控制管脚 sbit motor = P1^0; //电机控制引脚 sbit redLED = P3^4; sbit greenLED =P3^5; sbit yellowLED=P3^6; bit FLAG=0; int temp_value,set_temp=250; float T; unsigned char Key_set; unsigned char T1RH = 0; //T1 重载值的高字节 unsigned char T1RL = 0; //T1 重载值的低字节 /******************************************************************************* * 函 数 名 : Timer1_init * 函数功能 : 定时器初始化 * 输 入 : 无 * 输 出 : 无 * 说 名 : 该函数是在12MHZ晶振下,12分频单片机的延时。 *******************************************************************************/ void Timer1_init(void) { TMOD |= 0x10; //设置定时器模式 TL1 = 0x18; //设置定时初值 TH1 = 0xFC; //设置定时初值 TF1 = 0; //清除TF0标志 TR1 = 0; //定时器0先bu开始计时 ET1=0; //先不打开定时器中断 EA=1; PT1=0; } /******************************************************************************* * 函 数 名 : Show_temp * 函数功能 : 显示实时的温度 * 输 入 : 无 * 输 出 : 无 * 说 名 : 显示值为4位,其中保留一位小数。 *******************************************************************************/ void Show_temp() { temp_value=DS18B20_Read()*10; //读取温度,保留小数点后一位 if(((temp_value>set_temp-5) && (temp_value<set_temp+5)) && FLAG==0) //如果在±0.5摄氏度之间,电机没有工作 { StopBuzz(); //关闭蜂鸣器 motor=0; //关闭电机 Relay=1; //继电器断开 redLED = 0; // 将P3.4引脚输出低电平,红灯亮 greenLED =1; // 将P3.5引脚输出高电平,绿灯灭 } else if ((temp_value+5>set_temp && temp_value-5<set_temp) && FLAG==1) //如果在±0.5摄氏度之间,电机在工作 { OpenBuzz(); //打开蜂鸣器 motor=1; //打开电机 Relay=0; //继电器吸合 redLED = 1; greenLED =0; } else if(temp_value < set_temp-5) //如果电机工作,小于设定温度0.5摄氏度 { StopBuzz(); //关闭蜂鸣器 motor=0; //关闭电机 Relay=1; //继电器断开 FLAG=0; redLED = 1; greenLED =0; } else if(temp_value > set_temp+5) //如果大于设定温度0.5度 { OpenBuzz(); //打开蜂鸣器 motor=1; //打开电机 Relay=0; //继电器吸合 FLAG=1; redLED = 0; greenLED =1; } LCD_ShowString(1,1,"temp:"); LCD_ShowNum(1,6,temp_value/10,3); LCD_ShowChar(1,9,'.'); LCD_ShowNum(1,10,temp_value%10,1); LCD_ShowString(2,1,"set:"); LCD_ShowNum(2,5,set_temp/10,3); LCD_ShowChar(2,8,'.'); LCD_ShowNum(2,9,set_temp%10,1); } void main() { unsigned char KeyNum; Timer1_init(); //定时器初始化 StopBuzz(); //蜂鸣器不运转 LCD_Init(); //LCD初始化 DS18B20_ConvertT(); //上电先转换一次温度,防止第一次读数据错误 delay(1000); //等待转换完成 DS18B20_ConvertT(); //转换温度 while(1) { KeyNum=Key();//读取键码 switch (KeyNum) { case 1: set_temp++; break; case 2: set_temp--; break; } Show_temp(); //显示时间 } } void InterruptTimer1() interrupt 3 { static unsigned int T1Count; TL1 = 0x18; //设置定时初值 TH1 = 0xFC; //设置定时初值 T1Count++; if(T1Count>=500) { Buzzer_Time(100); T1Count=0; } } 代码中定时器的作用

完成一个仓储环境监测的模拟系统。具体要求如下: 1. DHT11模块完成温湿度测量,5s更新,数值显示于数码管,同时打印到串口。温度超过阈值触发蜂鸣器短鸣,同时启动风扇小马达; 2. LDR模块完成环境照度测量,4s更新,数值显示于数码管,同时打印到串口。照度超过阈值启动PWM调光(高、中、低三级调光)。 3. 按键循环切换显示模式,按第1下固定显示温度,按第二下固定显示照度,按第三下恢复默认的自动显示模式。按键用外部中断实现 int main(void) { systick_init(72); led_init(); usart1_init(115200); display_init(); tim4_init(1000,72); // 1ms的定时间隔 TIM3_CH2_PWM_Init(500-1,72-1); dht11_init(); ldr_init(); //key_init(); while(1) { // 轮询DHT11的状态 if(dht11.state == WORK) { if(dht11.getData(&dht11.temp, &dht11.humi) == SUCCESS) // DHT11温湿度数据更新 { printf("temperature:%d℃ humidity(RH):%d \r\n", dht11.temp, dht11.humi); dsp.interface = TEMP; dht11.onTempChange(dht11.temp_threshold); // 温度超过阈值的处理 } dht11.state = STANDBY; } // 轮询LDR的状态 if(ldr.state == WORK) { ldr.light = ldr.getData(); printf("light intensity:%d \r\n", ldr.light); dsp.interface = LIGHT; ldr.onLightChange(ldr.high_threshold,ldr.low_threshold); // 照度超过阈值的处理 ldr.state = STANDBY; } // 轮询数码管界面状态 switch(dsp.interface) { case LIGHT: setLightValue(&dsp,1); break; case TEMP: setTempValue(&dsp,1); break; case HUMI: setHumiValue(&dsp,1); break; default: break; } } }#include "systick.h" static u8 fac_us=0; //us延时倍乘数 static u16 fac_ms=0; //ms延时倍乘数 //初始化延迟函数 //SYSTICK的时钟固定为AHB时钟的1/8 //SYSCLK:系统时钟频率 void systick_init(u8 SYSCLK) { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); fac_us = SYSCLK/8; fac_ms = (u16)fac_us * 1000; } //延时nus //nus为要延时的us数. void delay_us(u32 nus) { u32 temp; SysTick->LOAD=nus*fac_us; //时间加载 SysTick->VAL=0x00; //清空计数器 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 do { temp=SysTick->CTRL; }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达 SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器 SysTick->VAL =0X00; //清空计数器 } //延时nms //注意nms的范围 //SysTick->LOAD为24位寄存器,所以,最大延时为: //nms<=0xffffff*8*1000/SYSCLK //SYSCLK单位为Hz,nms单位为ms //对72M条件下,nms<=1864 void delay_ms(u16 nms) { u32 temp; SysTick->LOAD = (u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit) SysTick->VAL = 0x00; //清空计数器 SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk ; //开始倒数 do { temp=SysTick->CTRL; } while((temp&0x01) && !(temp&(1<<16))); //等待时间到达 SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数器 SysTick->VAL = 0x00; //清空计数器 } #include "display.h" DisplayStruct dsp; void segDisplay(void); // 共阴极数码管,阴极位选(0有效),阳极段选(1有效) const u16 segCode[11] = { /* 0 1 2 3 4 5 6 7 */ 0x003F, 0x0006, 0x005B, 0x004F, 0x0066, 0x006D, 0x007D, 0x0007, /* 8 9 off */ 0x007F, 0x006F, 0x0000 }; /******************************************************************************* * @brief 初始化数码管用到的GPIO端口和dsp结构体 * @param None * @retval None *******************************************************************************/ void display_init(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE); // PA0~PA7: 段选(分别连接引脚A~G); // PB12~PB15:位选(分别连接引脚D1~D4) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); dsp.currDigit = 1; // dsp结构体的初始化 dsp.SegDisplay = segDisplay; } /*********************************************************************************** * @brief 设置数码管要显示的4位数值。 * @param dsp:数码管结构体指针;value[4]:4位数值;dotBit:小数点位置(没有小数点则置0) * @retval None ***********************************************************************************/ void setValue(DisplayStruct *dsp, u8 value[4], u8 dotBit) { dsp->digit[0] = value[0]; dsp->digit[1] = value[1]; dsp->digit[2] = value[2]; dsp->digit[3] = value[3]; dsp->dotDigit = dotBit; } void setLightValue(DisplayStruct *dsp, u8 dotBit) { dsp->digit[0] = 1; // 参数编号 dsp->digit[1] = 10; // 第二位空缺 dsp->digit[2] = ldr.light/10; dsp->digit[3] = ldr.light%10; // dsp->dotDigit = dotBit; // 小数点位置 } void setTempValue(DisplayStruct *dsp, u8 dotBit) { dsp->digit[0] = 2; dsp->digit[1] = 10; dsp->digit[2] = dht11.temp/10; dsp->digit[3] = dht11.temp%10; dsp->dotDigit = dotBit; } void setHumiValue(DisplayStruct *dsp, u8 dotBit) { dsp->digit[0] = 3; dsp->digit[1] = 10; dsp->digit[2] = dht11.humi/10; dsp->digit[3] = dht11.humi%10; dsp->dotDigit = dotBit; } /******************************************************************************* * @简 介 段选,让某一位数码管显示指定的数字 * @输入参数 value:段码数组的序号(0~9),代表要显示的数字 * @retval * 备注:只操作PA的低8位,不要影响高8位。 ********************************************************************************/ void seg(uint8_t value) { if(value < sizeof(segCode)) // 避免数组溢出 { GPIOA->ODR &= 0xFF00; GPIOA->ODR |= segCode[value]; } } /******************************************************************************** * 简 介 位选,一次只能选一位。 * 输入参数 com:位数(取值1~4,从左到右) * 返回值 无 * 备注:只操作PB的高4位(置0),不要影响其他位。 ********************************************************************************/ void com(uint8_t currDigit) { // 数码管位选(0有效) GPIOB->ODR |= 0xF000; GPIOB->ODR &= ~(0x1000<<(currDigit-1)); } /******************************************************************************** * 简介 在数码管上逐位显示其段码(由Timer中断服务函数调用) * 参数 无 * 返回值 无 ********************************************************************************/ void segDisplay(void) { seg(10); // 消隐之前的显示内容 com(dsp.currDigit); // 位选,从COM1到COM4逐次移位,实现动态显示 if(dsp.currDigit != dsp.dotDigit) // 当前位不显示小数点 seg(dsp.digit[dsp.currDigit-1]); else // 当前位要显示小数点 { GPIO_Write(GPIOA, segCode[dsp.digit[dsp.currDigit-1]]| 0x0080); //GPIOA->ODR &= 0xFF00; //GPIOA->ODR |= (segCode[dsp.currDigit-1]|0x0080); } if(++dsp.currDigit > DSP_DIGIT) // 从当前位右移到下一位 dsp.currDigit = 1; } #include "usart.h" int fputc(int ch,FILE *p) //函数默认的,在使用printf函数时自动调用 { USART_SendData(USART1,(u8)ch); while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); return ch; } //串口1中断服务程序 //注意,读取USARTx->SR能避免莫名其妙的错误 u8 USART1_RX_BUF[USART1_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节. //接收状态 //bit15, 接收完成标志 //bit14, 接收到0x0d //bit13~0, 接收到的有效字节数目 u16 USART1_RX_STA=0; //接收状态标记 /******************************************************************************* * 函 数 名 : USART1_Init * 函数功能 : USART1初始化函数 * 输 入 : bound:波特率 * 输 出 : 无 *******************************************************************************/ void usart1_init(u32 baud) { //GPIO端口设置 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); /* 配置GPIO的模式和IO口 */ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; //串口输出TX:PA9 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; //串口输入RX:PA10 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模拟输入 GPIO_Init(GPIOA,&GPIO_InitStructure); //USART1 初始化设置 USART_InitStructure.USART_BaudRate = baud; //波特率设置 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式 USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位 USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式 USART_Init(USART1, &USART_InitStructure); //初始化串口1 USART_Cmd(USART1, ENABLE); //使能串口1 USART_ClearFlag(USART1, USART_FLAG_TC); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断 //Usart1 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、 } /******************************************************************************* * 函 数 名 : USART1_IRQHandler * 函数功能 : USART1中断函数 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void USART1_IRQHandler(void) //串口1中断服务程序 { u8 r; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断 { r =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据 if((USART1_RX_STA&0x8000)==0)//接收未完成 { if(USART1_RX_STA&0x4000)//接收到了0x0d { if(r!=0x0a)USART1_RX_STA=0;//接收错误,重新开始 else USART1_RX_STA|=0x8000; //接收完成了 } else //还没收到0X0D { if(r==0x0d)USART1_RX_STA|=0x4000; else { USART1_RX_BUF[USART1_RX_STA&0X3FFF]=r; USART1_RX_STA++; if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;//接收数据错误,重新开始接收 } } } } } #include "timer.h" #include "beep.h" volatile uint16_t beep_time; /******************************************************************************* * 函 数 名 : tim4_init * 函数功能 : TIM4初始化函数 * 输 入 : per:重装载值 psc:分频系数 * 输 出 : 无 *******************************************************************************/ void tim4_init(u16 per,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); // 使能TIM4的时钟 // 配置TIM的时基参数 TIM_TimeBaseInitStructure.TIM_Period = per; // 自动装载值 TIM_TimeBaseInitStructure.TIM_Prescaler = psc; // 分频系数 TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; // 设置向上计数模式 TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure); // 设置参数生效 // 配置中断参数 TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); // 开启定时器的更新中断 TIM_ClearITPendingBit(TIM4,TIM_IT_Update); // 中断标志位清零 // 配置NVIC NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 中断优先级分组(组2) NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; // 定时器4的中断通道(30号通道) NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // 抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 响应优先级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 中断通道使能 NVIC_Init(&NVIC_InitStructure); // NVIC设置参数生效 TIM_Cmd(TIM4,ENABLE); // 使能Timer4 } /******************************************************************************* * 函 数 名 : TIM4_IRQHandler * 函数功能 : TIM4中断函数 * 输 入 : 无 * 输 出 : 无 * 备 注 : 定时间隔1ms ** *****************************************************************************/ void TIM4_IRQHandler(void) { static u16 cnt_dht11; static u16 cnt_ldr; // 蜂鸣器时间处理 if(beep_time > 0) { beep_time--; if(beep_time == 0) { BEEP_OFF(); } } if(TIM_GetITStatus(TIM4,TIM_IT_Update)) // 检查更新中断是否产生 { // 处理定时任务 if(++cnt_dht11 == dht11.period) { if(dht11.state == STANDBY) { dht11.state = WORK; // DHT11状态从STANDBY切换到WORK } cnt_dht11 = 0; } if(++cnt_ldr == ldr.period) { if (ldr.state == STANDBY) { ldr.state = WORK; // LDR状态从STANDBY切换到WORK } cnt_ldr = 0; } // 刷新数码管显示 dsp.SegDisplay(); } TIM_ClearITPendingBit(TIM4,TIM_IT_Update); // 手动清除中断标志位 } #include "dht11.h" #include "relay.h" #include "beep.h" Dht11Struct dht11 = {0}; void SET_DHT11_IO_OUT(void); void SET_DHT11_IO_IN(void); void DHT11_RequestData(void); u8 DHT11_RespondRequest(void); u8 DHT11_Read_Data(u8 *temp, u8 *humi); void DHT11_OnTempChange(u8 temp_threshold); // DHT11_PIN初始化 // 返回值: 无 extern void dht11_init() { GPIO_InitTypeDef GPIO_InitStructure; // 数据引脚初始化 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 数据引脚 GPIO_InitStructure.GPIO_Pin = DHT11_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(DHT11_PORT, &GPIO_InitStructure); GPIO_SetBits(DHT11_PORT, DHT11_PIN); // 初始输出状态:高电平 // 结构体初始化 dht11.period = DHT11_PERIOD; dht11.temp_threshold = TEMP_THRESHOLD; dht11.getData = DHT11_Read_Data; // 获取温湿度数据的函数 dht11.onTempChange = DHT11_OnTempChange; // 温度超过阈值的处理函数 // 做一次数据请求测试,检查设备状态 DHT11_RequestData(); if (DHT11_RespondRequest() == SUCCESS) { dht11.state = STANDBY; printf("DHT11 Init OK!\r\n"); } else { dht11.state = FAIL; printf("DHT11 Check Error!\r\n"); } } // 复位DHT11,单片机向DHT11发起数据采集请求 // 时序图的黑线部分 static void DHT11_RequestData() { SET_DHT11_IO_OUT(); // 数据引脚配置为输出模式 DHT11_DQ_OUT = 0; delay_ms(20); // 低电平持续至少18ms DHT11_DQ_OUT = 1; delay_us(30); // 高电平持续20~40us } // DHT11响应单片机的数据请求 // 返回值:SUCCESS or FAILURE static u8 DHT11_RespondRequest() { u8 retry=0; SET_DHT11_IO_IN(); // 数据引脚设为输入模式,接收DHT11的响应 while (DHT11_DQ_IN && retry<100) // 等待输入由高变低 { retry++; if(retry >= 100) return FAILURE; // 等待时间过长,返回异常。 delay_us(1); } retry=0; while (!DHT11_DQ_IN && retry<100) // 低电平持续时间80us { retry++; if(retry >= 100) return FAILURE; // 低电平持续时间过长,返回异常。 delay_us(1); } return SUCCESS; } //DHT11输出模式配置 static void SET_DHT11_IO_OUT() { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = DHT11_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(DHT11_PORT,&GPIO_InitStructure); } //DHT11输入模式配置 static void SET_DHT11_IO_IN() { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = DHT11_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入模式,最小系统板和DHT11之间并未接上拉电阻 GPIO_Init(DHT11_PORT,&GPIO_InitStructure); } //从DHT11读取一位 //返回值:bit 1或0 //注:此函数处并未做高低电平持续时间异常的处理,因DHT11自身有校验和,即便读错1位也不会造成最终数据的错误。 // 严格来讲,除了正常情况下返回“1”或“0”,还应增加异常情况的返回值(比如“2”)。 static u8 DHT11_Read_Bit(void) { u8 retry=0; while(DHT11_DQ_IN && retry<100) // 等待输入电平由高变低(低电平持续50us) { retry++; delay_us(1); } retry=0; while(!DHT11_DQ_IN && retry<100) // 等待输入电平由低变高 { retry++; delay_us(1); } delay_us(40); // 等待40us(高电平持续26~28us表示0,持续70us表示1) if(DHT11_DQ_IN) return 1; // 40us后如果输入仍为高电平,则表示读入1;否则表示读入0。 else return 0; } //从DHT11读取一个字节 //返回值:读到的8位数据 static u8 DHT11_Read_Byte(void) { u8 i,byte; byte = 0; for (i=0;i<8;i++) { byte <<= 1; // 先前读取的数据(不足8位)全部左移一位 byte |= DHT11_Read_Bit(); // 最低位填入新读取的1位 } return byte; } //从DHT11读取一次完整的数据 //temp:温度值(整数,范围:0~50°) //humi:湿度值(整数,范围:20%~90%) //返回值:0,正常; 1,失败 static u8 DHT11_Read_Data(u8 *temp, u8 *humi) { u8 buf[5]; u8 i; DHT11_RequestData(); if(DHT11_RespondRequest() == SUCCESS) { for(i=0;i<5;i++) // 读取5组共40位数据 { buf[i] = DHT11_Read_Byte(); } if((buf[0]+buf[1]+buf[2]+buf[3]) == buf[4]) // 数据校验 { *humi = buf[0]; // 湿度整数部分 *temp = buf[2]; // 温度整数部分 return SUCCESS; } } return FAILURE; } // 采集DHT11数据并打印至串口 void dht11DataCollect() { u8 temp; u8 humi; if (DHT11_Read_Data(&temp, &humi) == SUCCESS) printf("temperature:%d℃ humidity(RH):%d \r\n", temp, humi); // 输出到串口(重定向) else printf("DHT11 data error! \r\n"); } // 温度阈值处理 void DHT11_OnTempChange(u8 temp_threshold) { if (dht11.temp > temp_threshold) { // 启动风扇(继电器低电平触发) Relay_Low(); // 蜂鸣器短鸣(100ms) BEEP_ON(); beep_time = 100; // 100ms } else { // 关闭风扇 Relay_High(); } } #include "ldr.h" LdrStruct ldr; static u8 getLightIntensity(void); static void OnLightChange(u8 hiLight, u8 loLight); /******************************************************************************* * 函 数 名 : adc_init * 函数功能 : ADC外设的初始化 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ static void adc_init(void) { GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; // 1.打开相关外设的总线时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE); // 2.信号引脚的参数配置 GPIO_InitStructure.GPIO_Pin=LDR_PIN; // 信号引脚:PB0 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN; // 设置模拟输入模式 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz; // 设置传输速率 GPIO_Init(LDR_PORT,&GPIO_InitStructure); // 3. 输入时钟降频(<14MHz) RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 分频因子6,输入时钟为72M/6=12MHz // 4. 初始化ADC参数 ADC_InitStructure.ADC_Mode=ADC_Mode_Independent; //独立模式 ADC_InitStructure.ADC_ScanConvMode=DISABLE; //单次扫描 ADC_InitStructure.ADC_ContinuousConvMode=DISABLE; //单次转换 ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; //软件触发 ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right; //数据右对齐 ADC_InitStructure.ADC_NbrOfChannel=1; //只有1个通道 ADC_Init(ADC1,&ADC_InitStructure); // 5. 使能ADC ADC_Cmd(ADC1,ENABLE); // 6. ADC校准 ADC_ResetCalibration(ADC1); //复位校准 while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); //开启并完成校准 while(ADC_GetCalibrationStatus(ADC1)); } // LDR的设备初始化 extern void ldr_init() { adc_init(); ldr.period = LDR_PERIOD; ldr.high_threshold = HI_THRESHOLD; ldr.low_threshold = LO_THRESHOLD; ldr.getData = getLightIntensity; ldr.onLightChange = OnLightChange; ldr.state = STANDBY; } /******************************************************************************* * 函 数 名 : GET_ADC_Value * 函数功能 : 获取通道ch的转换值,测量times次,取平均值 * 输 入 : ch:通道编号,Rank:规则序列中的第几个转换,取值1~16; times:测量次数 * 输 出 : 通道ch的times次转换结果的平均值 *******************************************************************************/ static u16 Get_ADC_Value(u8 ch, u8 times) //获取ADC1通道ch的转换值 { u8 i; u32 Temp_val=0; ADC_RegularChannelConfig(ADC1,ch,1,ADC_SampleTime_239Cycles5); for(i=0;i<times;i++) { ADC_SoftwareStartConvCmd(ADC1,ENABLE); // 开始转换 while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)); // 等待至单次转换结束 Temp_val += ADC_GetConversionValue(ADC1); delay_ms(10); } return Temp_val/times; } /******************************************************************************* * 函 数 名 : getLightIntensity * 函数功能 : 将ADC转换值解读为光照强度 * 输 入 : 无 * 输 出 : 光照照度值(0~100, 0:照度最低;100:照度最高) *******************************************************************************/ static u8 getLightIntensity(void) //通过ADC1 通道0的值获取亮度值 { u16 value = 0; u8 lightvalue = 0; value = Get_ADC_Value(ADC_Channel_8,20); lightvalue = 100 - (u16)(value/40.95); return lightvalue; } // 添加PWM控制LED功能 static void set_led_brightness(u8 level) { switch(level) { case 0: // 低档 TIM_SetCompare2(TIM3, 125); // 25%占空比 break; case 1: // 中档 TIM_SetCompare2(TIM3, 250); // 50%占空比 break; case 2: // 高档 TIM_SetCompare2(TIM3, 375); // 75%占空比 break; } } /******************************************************************************* * 函 数 名 : OnLightChange * 函数功能 : 照度超过阈值(高阈值和低阈值)的处理措施 * 输 入 : hiLight-高阈值; loLight-低阈值 * 输 出 : 无 *******************************************************************************/ static void OnLightChange(u8 hiLight, u8 loLight) { if (ldr.light > hiLight) { set_led_brightness(0);// 照度过高,降低亮度 } else if (ldr.light < loLight) { set_led_brightness(2); // 照度过低,提升亮度 } else // 正常范围 { set_led_brightness(1); // 中等亮度 } } #include "key.h" #include "pwm.h" /******************************************************************************* * 函 数 名 : TIM3_CH2_PWM_Init * 函数功能 : TIM3通道2 PWM初始化函数 * 输 入 : per:重装载值 * psc:分频系数 * 输 出 : 无 *******************************************************************************/ void TIM3_CH2_PWM_Init(u16 per,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_OCInitTypeDef TIM_OCInitStructure; GPIO_InitTypeDef GPIO_InitStructure; /* 开启时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE); // PB5引脚启用复用模式 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); // 选择TIM3部分重映射 GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE); /* PB5作为PWM的输出引脚 */ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOB,&GPIO_InitStructure); // 初始化TIM3 TIM_TimeBaseInitStructure.TIM_Period=per; //自动装载值 TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式 TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure); // 设置TIM3_CH2的PWM模式,使能CH2输出,呈现出PPT展示的PWM波形 // PWM1即mode1,先输出有效电平,再输出无效电平;PWM2即mode2则正好相反。 TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1; // 设置有效电平为低电平(此案例中低电平点亮D2) TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low; TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable; TIM_OC2Init(TIM3,&TIM_OCInitStructure); //输出比较通道2初始化 TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能TIM3在 CCR2 上的预装载寄存器 TIM_Cmd(TIM3,ENABLE); //使能定时器 } #include "relay.h" void Relay_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStruct); //默认输出低电平 } void Relay_High(void) { GPIO_SetBits(GPIOA, GPIO_Pin_11); } void Relay_Low(void) { GPIO_ResetBits(GPIOA, GPIO_Pin_11); } #ifndef _RELAY_H_ #define _RELAY_H_ #include "main.h" #define RELAY_HIGH 1 #define RELAY_LOW 0 void Relay_Init(void); void Relay_High(void); void Relay_Low(void); #endif #ifndef __PWM_H #define __PWM_H #include "main.h" void TIM3_CH2_PWM_Init(u16 per,u16 psc); #endif #ifndef __LDR_H #define __LDR_H #include "main.h" #define LDR_PIN GPIO_Pin_0 #define LDR_PORT GPIOB #define LDR_PERIOD 4000 // ADC转换周期:4000ms #define HI_THRESHOLD 70 // 照度高阈值 #define LO_THRESHOLD 30 // 照度低阈值 typedef struct{ u8 light; // 光照强度(相对强度:0~100) u16 period; // 重复测量周期(s) u8 high_threshold; // 高亮阈值 u8 low_threshold; // 低亮阈值 SensorState state; // 工作状态 u8 (*getData)(void); // 获取光照强度数据 void (*onLightChange)(u8 hiLight, u8 loLight); // 亮度变化的响应操作 } LdrStruct; void ldr_init(void); extern LdrStruct ldr; #endif #ifndef __DHT11_H #define __DHT11_H #include "main.h" #define DHT11_PIN GPIO_Pin_12 #define DHT11_PORT GPIOA #define DHT11_DQ_IN PCin(12) // 输入 #define DHT11_DQ_OUT PCout(12) // 输出 #define SUCCESS 0 #define FAILURE 1 #define DHT11_PERIOD 5000 // 数据采集周期:5000ms #define TEMP_THRESHOLD 28 // 温度阈值(℃) // 定义DHT11结构体 typedef struct{ u8 temp; // 温度值 u8 humi; // 湿度值 u16 period; // 重复测量周期(s) u8 temp_threshold; // 温度阈值 u8 humi_threshold; // 湿度阈值 SensorState state; // 设备状态 u8 (*getData)(u8 *temp, u8 *humi); // 获取温湿度数据 void (*onTempChange)(u8 temp_threshold); // 高温的响应操作 } Dht11Struct; void dht11_init(void); extern Dht11Struct dht11; #endif #ifndef _usart_H #define _usart_H #include "main.h" #define USART1_REC_LEN 200 //定义最大接收字节数 200 extern u8 USART1_RX_BUF[USART1_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 extern u16 USART1_RX_STA; //接收状态标记 void usart1_init(u32 baud); #endif #ifndef __TIM_H #define __TIM_H #include "main.h" //#include "stm32f10x.h" void tim4_init(u16 per,u16 psc); #endif #ifndef __DISPLAY_H #define __DISPLAY_H #include "main.h" #define DSP_DIGIT 4 // 4位数码管 typedef enum{LIGHT, TEMP, HUMI} DSP_Interface; // 数码管界面 typedef struct { u16 digit[DSP_DIGIT]; // 数码管的4位数字 u8 currDigit; // 当前显示位(1~4) u8 dotDigit; // 小数点位置(0~4,0代表不显示小数点) DSP_Interface interface; // 界面显示哪个测量值 void(*SegDisplay)(void); }DisplayStruct; void display_init(void); void segDisplay(void); //void setValue(DisplayStruct *dsp, u8 value[4], u8 dotBit); void setLightValue(DisplayStruct *dsp, u8 dotBit); void setTempValue(DisplayStruct *dsp, u8 dotBit); void setHumiValue(DisplayStruct *dsp, u8 dotBit); extern DisplayStruct dsp; #endif 在已有代码上完善该任务,STM32F103C8t6,用标准库

#include <reg52.h> #define uchar unsigned char #define uint unsigned int // 数码管段选定义 uchar code smg_du[]={0x14,0x77,0x4c,0x45,0x27,0x85,0x84,0x57,0x04,0x05}; // 0-9段码 uchar dis_smg[4] = {0xff,0xff,0xff,0xff}; // 数码管显示缓冲区 sbit dq = P1^6; // DS18B20数据线 sbit beep = P3^3; // 蜂鸣器 sbit key1 = P3^5; // 设置键 sbit key2 = P3^6; // 加键 sbit key3 = P3^7; // 减键 uchar flag_lj_en; // 按键连加标志 uint temperature; // 当前温度值 bit flag_300ms; // 300ms标志 uchar menu_1; // 菜单状态 uint t_high = 350, t_low = 100; // 温度上下限 // 数码管位选 sbit smg_we1 = P2^0; sbit smg_we2 = P2^2; sbit smg_we3 = P2^4; sbit smg_we4 = P2^6; sbit relay1 = P1^5; // 低温继电器 sbit relay2 = P1^3; // 高温继电器 // 新增变量 float temp_buffer[5]; // 温度缓冲区 uchar temp_index = 0; // 缓冲区索引 bit temp_stable_flag = 0; // 温度稳定标志 bit beep_flag = 0; // 蜂鸣器标志 uchar beep_count = 0; // 蜂鸣计数 #define BEEP_DURATION 250 // 蜂鸣持续时间(ms) #define BEEP_INTERVAL 500 // 蜂鸣间隔(ms) /*********************** 数码管位选函数 *****************************/ void smg_we_switch(uchar i) { smg_we1 = 1; smg_we2 = 1; smg_we3 = 1; smg_we4 = 1; switch(i) { case 0: smg_we1 = 0; break; case 1: smg_we2 = 0; break; case 2: smg_we3 = 0; break; case 3: smg_we4 = 0; break; } } /*********************** 延时函数 *****************************/ void delay_1ms(uint q) { uint i,j; for(i=0;i<q;i++) for(j=0;j<120;j++); } void delay_uint(uint q) { while(q--); } /*********************** 数码管显示函数 *****************************/ void display() { static uchar i; i++; if(i >= 4) i = 0; P0 = 0xff; // 消隐 delay_uint(10); // 短暂延时 smg_we_switch(i); P0 = dis_smg[i]; } /*********************** DS18B20初始化 *****************************/ bit init_18b20() { bit presence; dq = 1; delay_uint(1); dq = 0; delay_uint(80); // 480us dq = 1; delay_uint(10); // 等待60us presence = dq; delay_uint(20); dq = 1; return presence; } /*********************** 写DS18B20 *****************************/ void write_18b20(uchar dat) { uchar i; for(i=0;i<8;i++) { dq = 0; dq = dat & 0x01; delay_uint(5); // 60us dq = 1; dat >>= 1; } } /*********************** 读DS18B20 *****************************/ uchar read_18b20() { uchar i,value=0; for(i=0;i<8;i++) { dq = 0; value >>= 1; dq = 1; if(dq) value |= 0x80; delay_uint(5); // 60us } return value; } /*********************** 读取温度值 *****************************/ uint read_temp() { uint value; uchar low; if(!init_18b20()) return 0xFFFF; // 初始化失败 EA = 0; write_18b20(0xCC); // 跳过ROM write_18b20(0x44); // 开始转换 delay_uint(50); // 等待转换 if(!init_18b20()) { EA = 1; return 0xFFFF; // 初始化失败 } write_18b20(0xCC); // 跳过ROM write_18b20(0xBE); // 读暂存器 low = read_18b20(); value = read_18b20(); EA = 1; value = (value << 8) | low; // 转换为实际温度值 (0.625°C/LSB) value = (value >> 4)*10 + ((value & 0x0F)*625)/1000; return value; } /*********************** 温度稳定性检测 *****************************/ void check_temperature_stability() { static uint max_temp, min_temp; uchar i; uchar valid_count; temp_buffer[temp_index++] = temperature; if(temp_index >= 5) temp_index = 0; // 缓冲区未满时不检测 valid_count = 0; if(valid_count < 5) { valid_count++; return; } max_temp = min_temp = temp_buffer[0]; for(i=1; i<5; i++) { if(temp_buffer[i] > max_temp) max_temp = temp_buffer[i]; if(temp_buffer[i] < min_temp) min_temp = temp_buffer[i]; } // 判断温度是否稳定 if((max_temp - min_temp) <= 5) { // 0.5°C阈值 temp_stable_flag = 1; } else { temp_stable_flag = 0; } } /*********************** 按键处理 *****************************/ uchar key_can = 0; void key() { static uchar key_time = 0; key_can = 0; if((key1 == 0) || (key2 == 0) || (key3 == 0)) { delay_1ms(20); // 消抖 if(key1 == 0) key_can = 1; if(key2 == 0) key_can = 2; if(key3 == 0) key_can = 3; // 连加处理 if(++key_time > 10) { // 长按加速 flag_lj_en = 2; if(key_time > 30) flag_lj_en = 5; } } else { key_time = 0; flag_lj_en = 0; } } /*********************** 按键功能处理 *****************************/ void key_with() { if(key_can == 1) { // 设置键 menu_1++; if(menu_1 > 2) menu_1 = 0; } if(menu_1 == 1) { // 设置上限 if(key_can == 2) { // 加 t_high += (flag_lj_en ? flag_lj_en : 1); if(t_high > 999) t_high = 999; if(t_high <= t_low) t_high = t_low + 1; } if(key_can == 3) { // 减 t_high -= (flag_lj_en ? flag_lj_en : 1); if(t_high <= t_low) t_high = t_low + 1; } dis_smg[0] = smg_du[t_high % 10]; dis_smg[1] = smg_du[t_high / 10 % 10] & 0xFB; dis_smg[2] = smg_du[t_high / 100 % 10]; dis_smg[3] = 0x26; // H } else if(menu_1 == 2) { // 设置下限 if(key_can == 2) { // 加 t_low += (flag_lj_en ? flag_lj_en : 1); if(t_low >= t_high) t_low = t_high - 1; } if(key_can == 3) { // 减 t_low -= (flag_lj_en ? flag_lj_en : 1); if(t_low < 10) t_low = 10; } dis_smg[0] = smg_du[t_low % 10]; dis_smg[1] = smg_du[t_low / 10 % 10] & 0xFB; dis_smg[2] = smg_du[t_low / 100 % 10]; dis_smg[3] = 0xBC; // L } delay_1ms(300); } /*********************** 报警控制 *****************************/ void clock_h_l() { static bit last_state = 0; if(temperature <= t_low) { relay1 = 0; // 开启低温继电器 relay2 = 1; // 确保高温继电器关闭 if(last_state != 1) { last_state = 1; beep_flag = 1; // 触发报警 } } else if(temperature >= t_high) { relay2 = 0; // 开启高温继电器 relay1 = 1; // 确保低温继电器关闭 if(last_state != 2) { last_state = 2; beep_flag = 1; // 触发报警 } } else { relay1 = relay2 = 1; // 关闭所有继电器 last_state = 0; } } /*********************** 定时器0初始化 *****************************/ void time_init() { EA = 1; TMOD = 0x01; ET0 = 1; TR0 = 1; TH0 = 0xF8; TL0 = 0x30; // 2ms定时 } /*********************** 主函数 *****************************/ void main() { // 初始化 P0 = P1 = P2 = P3 = 0xFF; relay1 = relay2 = 1; // 继电器初始关闭 beep = 1; // 蜂鸣器初始关闭 // 初始温度读取 temperature = read_temp(); delay_1ms(750); temperature = read_temp(); time_init(); // 定时器初始化 while(1) { key(); // 按键扫描 if(key_can > 0) { key_with(); // 按键处理 if(menu_1 == 0 && key_can == 3) { beep = 1; // 手动关闭蜂鸣器 beep_flag = 0; } } if(flag_300ms ) { flag_300ms = 0; // 读取温度 uchar temp_count = 0; if(++temp_count >= 15) { // 约300ms读一次 temp_count = 0; temperature = read_temp(); check_temperature_stability(); } // 显示处理 if(menu_1 == 0) { dis_smg[0] = smg_du[temperature % 10]; dis_smg[1] = smg_du[temperature / 10 % 10] & 0xFB; dis_smg[2] = smg_du[temperature / 100 % 10]; dis_smg[3] = 0xFF; } // 报警控制 if(temp_stable_flag) { clock_h_l(); } } delay_1ms(1); } } /*********************** 定时器0中断 *****************************/ void time0_int() interrupt 1 { static uint ms_count = 0; static uchar beep_timer = 0; TH0 = 0xF8; TL0 = 0x30; // 重装2ms定时 // 数码管显示 display(); // 300ms定时 if(++ms_count >= 150) { ms_count = 0; flag_300ms = 1; } // 蜂鸣器控制 if(beep_flag && beep_count < 3) { if(++beep_timer >= BEEP_DURATION/2) { beep_timer = 0; beep = ~beep; if(beep == 1) { beep_count++; if(beep_count >= 3) { beep_flag = 0; beep_count = 0; } } } } else { beep = 1; } }

#include <reg52.h> //调用单片机头文件 #include <math.h> #define uchar unsigned char //无符号字符型 宏定义 变量范围0~255 #define uint unsigned int //无符号整型 宏定义 变量范围0~65535 //数码管段选定义 0 1 2 3 4 5 6 7 8 9 uchar code smg_du[]={0x14,0x77,0x4c,0x45,0x27,0x85,0x84,0x57,0x04,0x05}; //段码 uchar dis_smg[4] = {0xff,0xff,0xff,0xff}; //数码管显示数组的缓冲区 sbit dq = P1^6; //18b20 IO口的定义 sbit beep = P3^3; //蜂鸣器IO口定义 sbit key1 = P3^5; //按键IO口定义 sbit key2 = P3^6; //按键IO口定义 sbit key3 = P3^7; //按键IO口定义 uchar flag_lj_en; //按键连加变量 uint temperature ; //温度变量 bit flag_300ms ; //300毫秒的变量 uchar menu_1; //设置不同报警参数的变量 uint t_high = 350,t_low = 100; //温度上下限报警值 // 全局变量定义 uint temperature; // 当前温度 uint temp_buffer[10]; // 温度缓冲区 uchar temp_count = 0; // 温度计数器 bit flag_stable_check = 0; // 稳定检查标志位 uint temperature_c; // 当前温度(摄氏度) uint temperature_f; // 当前温度(华氏度) uchar unit_flag = 0; // 温度单位标志位 0: 摄氏度, 1: 华氏度 sbit zhengzhuan = P2^2; // 正转控制引脚 sbit shineng = P2^0; // 使能控制引脚 static uint stability_check_delay = 0; //数码管位选定义 sbit smg_we1 = P2^0; //数码管位选IO口定义 sbit smg_we2 = P2^2; //数码管位选IO口定义 sbit smg_we3 = P2^4; //数码管位选IO口定义 sbit smg_we4 = P2^6; //数码管位选IO口定义 sbit relay1 = P1^5; //继电器1 IO口定义 sbit relay2 = P1^3; //继电器2 IO口定义 uchar flag_en = 1; /***********************数码位选函数*****************************/ void smg_we_switch(uchar i) { switch(i) { case 0: smg_we1 = 0; smg_we2 = 1; smg_we3 = 1; smg_we4 = 1; break; case 1: smg_we1 = 1; smg_we2 = 0; smg_we3 = 1; smg_we4 = 1; break; case 2: smg_we1 = 1; smg_we2 = 1; smg_we3 = 0; smg_we4 = 1; break; case 3: smg_we1 = 1; smg_we2 = 1; smg_we3 = 1; smg_we4 = 0; break; } } /***********************1ms延时函数*****************************/ void delay_1ms(uint q) { uint i,j; for(i=0;i<q;i++) for(j=0;j<120;j++); } /***********************小延时函数*****************************/ void delay_uint(uint q) { while(q--); } /***********************数码显示函数*****************************/ void display() { static uchar i; i++; if(i >= 4) i = 0; P0 = 0xff; //消隐 smg_we_switch(i); //位选 P0 = dis_smg[i]; //段选 } /***********************18b20初始化函数*****************************/ void init_18b20() { bit q; dq = 1; //把总线拿高 delay_uint(1); dq = 0; //给复位脉冲 delay_uint(80); dq = 1; //把总线拿高 等待 delay_uint(10); q = dq; //读取18b20初始化信号 delay_uint(20); dq = 1; //把总线拿高 释放总线 } /*************写18b20内的数据***************/ void write_18b20(uchar dat) { uchar i; for(i=0;i<8;i++) { //写数据是低位开始 dq = 0; //把总线拿低写时间隙开始 dq = dat & 0x01; //向18b20总线写数据了 delay_uint(5); // 60us dq = 1; //释放总线 dat >>= 1; } } /*************读取18b20内的数据***************/ uchar read_18b20() { uchar i,value; for(i=0;i<8;i++) { dq = 0; //把总线拿低读时间隙开始 value >>= 1; //读数据是低位开始 dq = 1; //释放总线 if(dq == 1) //开始读写数据 value |= 0x80; delay_uint(5); //60us 读一个时间隙最少要保持60us的时间 } return value; //返回数据 } /*************读取温度的值 读出来的是小数***************/ uint read_temp() { uint value; uchar low; //在读取温度的时候如果中断的太频繁了,就应该把中断给关了,否则会影响到18b20的时序 init_18b20(); //初始化18b20 write_18b20(0xcc); //跳过64位ROM write_18b20(0x44); //启动一次温度转换命令 delay_uint(50); //500us EA = 0; init_18b20(); //初始化18b20 write_18b20(0xcc); //跳过64位ROM write_18b20(0xbe); //发出读取暂存器命令 low = read_18b20(); //读温度低字节 value = read_18b20(); //读温度高字节 EA = 1; value <<= 8; //把温度的高位左移8位 value |= low; //把读出的温度低位放到value的低八位中 value *= 0.625; //转换到温度值 小数 return value; //返回读出的温度 } /*************定时器0初始化程序***************/ void time_init() { EA = 1; //开总中断 TMOD = 0X01; //定时器0、定时器1工作方式1 ET0 = 1; //开定时器0中断 TR0 = 1; //允许定时器0定时 TH0 = 0xf8; TL0 = 0x30; //2ms } /********************独立按键程序*****************/ uchar key_can; // 按键值 uchar key_delay; // 按键延时计数器 void key() // 独立按键程序 { key_can = 0; // 按键值还原成0 if(key1 == 0 || key2 == 0 || key3 == 0) // 有按键按下 { delay_1ms(10); // 按键延时消抖动 if(key1 == 0) // 确认是按键按下 key_can = 1; // 得到按键值 if(key2 == 0) // 确认是按键按下 key_can = 2; // 得到按键值 if(key3 == 0) // 确认是按键按下 key_can = 3; // 得到按键值 if(++key_delay >= 5) // 连续按键超过5次触发连加/连减 { flag_lj_en = 1; // 开启连加/连减模式 } } else { flag_lj_en = 0; // 关闭连加/连减模式 key_delay = 0; // 清零延时计数器 } } /****************按键处理数码管显示函数***************/ void key_with() { if(key_can == 1) //设置键 { menu_1 ++; if(menu_1 >= 3) { menu_1 = 0; //menu_1 = 0 退出设置了, } } if(menu_1 == 1) //设置温度上限报警值 { if(key_can == 2) //加键 { if(flag_lj_en <= 3) t_high ++ ; //按键按下未松开加1 加三次 else t_high += 10; //按键按下未松开加三次后加10 if(t_high > 999) t_high = 999; } if(key_can == 3) //减键 { if(flag_lj_en <= 3) t_high -- ; //按键按下未松开减1 减三次 else t_high -= 10; //按键按下未松开减三次后减10 if(t_high <= t_low) t_high = t_low + 1; //限制温度上限不能低于温度下限 } dis_smg[0] = smg_du[t_high % 10]; //取小数显示 dis_smg[1] = smg_du[t_high / 10 % 10] & 0xfb; //取个位显示 dis_smg[2] = smg_du[t_high / 100 % 10] ; //取十位显示 dis_smg[3] = 0x26; //显示H } if(menu_1 == 2) //设置温度下限报警值 { if(key_can == 2) //加键 { if(flag_lj_en <= 3) t_low ++ ; //按键按下未松开加1 加三次 else t_low += 10; //按键按下未松开加三次后加10 if(t_low >= t_high) t_low = t_high - 1; //限制温度下限不能高于温度上限 } if(key_can == 3) //减键 { if(flag_lj_en <= 3) t_low -- ; //按键按下未松开减1 减三次 else t_low -= 10; //按键按下未松开减三次后减10 if(t_low <= 10) t_low = 10; } dis_smg[0] = smg_du[t_low % 10]; //取小数显示 dis_smg[1] = smg_du[t_low / 10 % 10] & 0xfb; //取个位显示 dis_smg[2] = smg_du[t_low / 100 % 10] ; //取十位显示 dis_smg[3] = 0xBC; //显示L } delay_1ms(400); } /****************报警函数***************/ void clock_h_l() { if( temperature >= t_high) //温度大于等于上限 { if(flag_en == 1) beep = ~beep; //蜂鸣器报警 if(temperature >= t_high) relay2 = 0; //打开继电器 } else { beep = 1; //取消报警 relay2 = 1; //关闭继电器 flag_en = 1; } } void motor() { // 直流电机函数 relay1 = 0; delay_1ms(3000); relay1 = 1; } /****************更新温度显示***************/ void update_temperature_display() { uint tem,tem1; temperature_c = (read_temp()); // 读取摄氏温度 tem = (temperature_c*18) + 3200;// 转换为华氏温度 tem1=tem/10; temperature_f=tem1; if(unit_flag == 0) // 显示摄氏度 { dis_smg[0] = smg_du[temperature_c % 10]; // 小数部分 dis_smg[1] = smg_du[temperature_c / 10 % 10] & 0xfb; // 个位 dis_smg[2] = smg_du[temperature_c / 100 % 10]; // 十位 dis_smg[3] = 0xFF; // 不显示符号 } else // 显示华氏度 { dis_smg[0] = smg_du[temperature_f % 10]; // 小数部分 dis_smg[1] = smg_du[temperature_f / 10 % 10] & 0xfb; // 个位 dis_smg[2] = smg_du[temperature_f / 100 % 10]; // 十位 dis_smg[3] = smg_du[temperature_f / 1000 % 10]; } } /****************主函数***************/ void main() { beep = 0; // 开机叫一声 delay_1ms(150); P0 = P1 = P2 = P3 = 0xff; // 所有单片机IO口输出高电平 time_init(); // 初始化定时器 while(1) { key(); // 按键程序 if(key_can > 0) { key_with(); // 设置温度上下限值 if(menu_1 == 0) { if(key_can == 3) { flag_en = 0; // 手动取消报警 beep = 1; // 关闭蜂鸣器 } } } if(flag_300ms == 1) // 300ms 处理一次温度程序 { flag_300ms = 0; read_temp_into_buffer(); // 将温度读入缓冲区 if(temp_count >= 5) { check_temperature_stability();// 检查温度稳定性 temp_count = 0; // 重置计数器 } } // if(temp_count >= 5) // 如果已经收集了5个温度值 // { // check_temperature_stability(); // 检查温度稳定性 // temp_count = 0; // 重置计数器 // } // 实时更新数码管显示 if(menu_1 == 0) { if(key_can == 3) // 按键3用于切换温度单位 { unit_flag = !unit_flag; // 切换标志位 } update_temperature_display(); // 更新显示 } } delay_1ms(1); } /*************定时器0中断服务程序***************/ void time0_int() interrupt 1 { static uchar value; //定时2ms中断一次 TH0 = 0xf8; TL0 = 0x30; //2ms display(); //数码管显示函数 value++; if(value >= 150) { value = 0; flag_300ms = 1; //定时产生一个300毫秒的变量 } } 描述上面程序的按键模块功能

最新推荐

recommend-type

深度学习通用模块精选集

这份资源是一套聚焦深度学习领域的通用模块精选集,整合了从经典到近年前沿的 50 个核心组件(如注意力机制、特征增强模块、上下文建模单元等),覆盖目标检测、语义分割、域自适应等多个任务场景。 每个模块均严格从对应论文中提炼核心信息,按 “作用 - 机制 - 独特优势 - 带注释代码” 四部分结构化呈现: 明确模块解决的具体问题(如提升小目标检测精度、增强上下文感知能力); 拆解其工作逻辑(如多分支特征融合、循环注意力机制等); 总结相比同类方法的创新点(如轻量化设计、更高计算效率); 提供可直接运行的代码实现,注释详尽且适配主流框架(PyTorch 为主)。 资源旨在为研究者和开发者提供 “即插即用” 的工具包:无需逐篇翻阅论文,即可快速理解模块原理并嵌入自有网络测试效果,尤其适合赶实验、调模型或撰写论文时的模块选型与整合,助力高效完成 “模块缝合” 与性能优化。
recommend-type

500强企业管理表格模板大全

在当今商业环境中,管理表格作为企业运营和管理的重要工具,是确保组织高效运作的关键。世界500强企业在管理层面的成功,很大程度上得益于它们的规范化和精细化管理。本文件介绍的“世界500强企业管理表格经典”,是一份集合了多种管理表格模板的资源,能够帮助管理者们更有效地进行企业规划、执行和监控。 首先,“管理表格”这个概念在企业中通常指的是用于记录、分析、决策和沟通的各种文档和图表。这些表格不仅仅局限于纸质形式,更多地是以电子形式存在,如Excel、Word、PDF等文件格式。它们帮助企业管理者收集和整理数据,以及可视化信息,从而做出更加精准的决策。管理表格可以应用于多个领域,例如人力资源管理、财务预算、项目管理、销售统计等。 标题中提及的“世界500强”,即指那些在全球范围内运营且在《财富》杂志每年公布的全球500强企业排行榜上出现的大型公司。这些企业通常具备较为成熟和先进的管理理念,其管理表格往往经过长时间的实践检验,并且能够有效地提高工作效率和决策质量。 描述中提到的“规范化”是企业管理中的一个核心概念。规范化指的是制定明确的标准和流程,以确保各项管理活动的一致性和可预测性。管理表格的使用能够帮助实现管理规范化,使得管理工作有据可依、有章可循,减少因个人经验和随意性带来的风险和不确定性。规范化管理不仅提高了企业的透明度,还有利于培养员工的规则意识,加强团队之间的协调与合作。 “经典”一词在这里强调的是,这些管理表格模板是经过实践验证,能够适用于大多数管理场景的基本模式。由于它们的普适性和高效性,这些表格模板被广泛应用于不同行业和不同规模的企业之中。一个典型的例子是SWOT分析表,它可以帮助企业识别内部的优势(Strengths)、弱点(Weaknesses)以及外部的机会(Opportunities)和威胁(Threats)。SWOT分析表就是一个在世界500强企业中普遍使用的管理表格。 标签中的“表格模板”则是对上述管理工具的具体描述。这些模板通常是预先设计好的,能够帮助企业管理者快速开始工作,无需从零开始制作新的表格。它们包含了一些必备的字段和格式,用户可以根据自己的具体需求对模板进行调整和填充。 文件名称列表中的“index.html”可能是压缩包内的一个网页文件,用于展示管理表格的索引或介绍。如果这是一个在线资源,它将允许用户通过网页界面访问和下载各种表格模板。而“menu”可能是一个导航文件,用来帮助用户在多个表格模板之间进行选择。“data”文件夹可能包含了实际的表格模板文件,它们可能以Excel、Word等格式存在。 总的来说,管理表格是企业成功管理不可或缺的工具。通过使用世界500强企业所采纳的管理表格模板,其他企业可以借鉴这些顶级企业的管理经验,帮助自己在管理实践中达到更高的效率和质量。通过规范化和模板化的管理表格,企业可以确保其管理活动的一致性和标准化,这对于保持竞争力和实现长期发展至关重要。
recommend-type

YOLOv8目标检测算法深度剖析:从零开始构建高效检测系统(10大秘诀)

# 1. YOLOv8目标检测算法概述 ## 1.1 YOLOv8的简介与定位 YOLOv8(You Only Look Once version 8)作为一种前沿的目标检测算法,是由YOLO系列算法演化而来。该算法特别强调快速与准确的平衡,它被设计用于实时图像识别
recommend-type

mclmcrrt9_8.dll下载

<think>我们正在处理用户关于"mclmcrrt9_8.dll"文件的下载请求。根据引用内容,这个文件是MATLAB运行时库的一部分,通常与特定版本的MATLABRuntime相关联。用户需求:下载mclmcrrt9_8.dll的官方版本。分析:1.根据引用[2]和[3],mclmcrrt9_0_1.dll和mclmcrrt9_13.dll都是MATLABRuntime的文件,版本号对应MATLAB的版本(如9_0对应R2016a,9_13对应2022b)。2.因此,mclmcrrt9_8.dll应该对应于某个特定版本的MATLAB(可能是R2016b?因为9.8版本通常对应MATLABR
recommend-type

林锐博士C++编程指南与心得:初学者快速提能

首先,这份文件的核心在于学习和提高C++编程能力,特别是针对初学者。在这个过程中,需要掌握的不仅仅是编程语法和基本结构,更多的是理解和运用这些知识来解决实际问题。下面将详细解释一些重要的知识点。 ### 1. 学习C++基础知识 - **基本数据类型**: 在C++中,需要熟悉整型、浮点型、字符型等数据类型,以及它们的使用和相互转换。 - **变量与常量**: 学习如何声明变量和常量,并理解它们在程序中的作用。 - **控制结构**: 包括条件语句(if-else)、循环语句(for、while、do-while),它们是构成程序逻辑的关键。 - **函数**: 理解函数定义、声明、调用和参数传递机制,是组织代码的重要手段。 - **数组和指针**: 学习如何使用数组存储数据,以及指针的声明、初始化和运算,这是C++中的高级话题。 ### 2. 林锐博士的《高质量的C++编程指南》 林锐博士的著作《高质量的C++编程指南》是C++学习者的重要参考资料。这本书主要覆盖了以下内容: - **编码规范**: 包括命名规则、注释习惯、文件结构等,这些都是编写可读性和可维护性代码的基础。 - **设计模式**: 在C++中合理使用设计模式可以提高代码的复用性和可维护性。 - **性能优化**: 学习如何编写效率更高、资源占用更少的代码。 - **错误处理**: 包括异常处理和错误检测机制,这对于提高程序的鲁棒性至关重要。 - **资源管理**: 学习如何在C++中管理资源,避免内存泄漏等常见错误。 ### 3. 答题与测试 - **C++C试题**: 通过阅读并回答相关试题,可以帮助读者巩固所学知识,并且学会如何将理论应用到实际问题中。 - **答案与评分标准**: 提供答案和评分标准,使读者能够自我评估学习成果,了解哪些方面需要进一步加强。 ### 4. 心得体会与实践 - **实践**: 理论知识需要通过大量编程实践来加深理解,动手编写代码,解决问题,是学习编程的重要方式。 - **阅读源码**: 阅读其他人的高质量代码,可以学习到许多编程技巧和最佳实践。 - **学习社区**: 参与C++相关社区,比如Stack Overflow、C++论坛等,可以帮助解答疑惑,交流心得。 ### 5. 拓展知识 - **C++标准库**: 学习C++标准模板库(STL),包括vector、map、list、algorithm等常用组件,是构建复杂数据结构和算法的基础。 - **面向对象编程**: C++是一种面向对象的编程语言,理解类、对象、继承、多态等概念对于写出优雅的C++代码至关重要。 - **跨平台编程**: 了解不同操作系统(如Windows、Linux)上的C++编程差异,学习如何编写跨平台的应用程序。 - **现代C++特性**: 学习C++11、C++14、C++17甚至C++20中的新特性,如智能指针、lambda表达式、自动类型推导等,可以提高开发效率和代码质量。 ### 总结 学习C++是一个系统工程,需要从基础语法开始,逐步深入到设计思想、性能优化、跨平台编程等领域。通过不断的学习和实践,初学者可以逐步成长为一个具有高代码质量意识的C++程序员。而通过阅读经典指南书籍,参与测试与评估,以及反思和总结实践经验,读者将更加扎实地掌握C++编程技术。此外,还需注意编程社区的交流和现代C++的发展趋势,这些都对于保持编程技能的前沿性和实用性是必不可少的。
recommend-type

线性代数方程组求解全攻略:直接法vs迭代法,一文搞懂

# 摘要 线性代数方程组求解是数学和工程领域中的基础而重要的问题。本文首先介绍了线性方程组求解的基础知识,然后详细阐述了直接法和迭代法两种主要的求解策略。直接法包括高斯消元法和LU分解方法,本文探讨了其理论基础、实践应用以及算法优化。迭代法则聚焦于雅可比和高斯-赛德尔方法,分析了其原理、实践应用和收敛性。通过比较分析,本文讨论了两种方法在
recommend-type

怎么下载mysql8.0.33版本

<think>我们正在处理用户关于下载并安装MySQL8.0.33版本的问题。根据引用[1]和引用[2],我们可以提供两种方法:一种是使用RPM包在CentOS上安装,另一种是使用ZIP包在Windows上安装。另外,引用[3]提到了安装过程中需要注意Python环境,但根据MySQL官方文档,Python并不是必须的,除非使用某些特定功能(如MySQLShell的Python模式)。因此,我们主要关注下载和安装步骤。用户没有明确操作系统,因此我们将分别介绍Windows和CentOS(Linux)下的安装方法。步骤概述:1.下载MySQL8.0.332.安装(根据系统不同步骤不同)3.初始化
recommend-type

C#学籍管理系统开发完成,信管专业的福音

标题中提到的“C#设计的学籍系统”涉及到几个重要的知识点。首先是“C#”,这是微软公司开发的一种面向对象的、运行在.NET框架上的高级编程语言。C#语言广泛用于开发Windows应用程序、游戏开发、分布式组件和客户端服务器应用程序等。在该标题中,它被用于构建一个学籍系统,这意味着系统的核心逻辑和功能是通过C#语言实现的。 其次是“学籍系统”,这通常是指用于管理学生个人信息、成绩、课程和学籍状态等数据的软件应用系统。学籍系统能够帮助教育机构高效地维护和更新学生档案,实现学生信息的电子化管理。它通常包括学生信息管理、成绩管理、课程安排、毕业资格审核等功能。 从描述中我们可以得知,这个学籍系统是“专门为信管打造”的。这里的“信管”很可能是对“信息管理”或者“信息系统管理”专业的简称。信息管理是一个跨学科领域,涉及信息技术在收集、存储、保护、处理、传输和安全地管理和开发信息资源方面的应用。这个系统可能是针对该专业学生的实际需求来定制开发的,包括一些特有的功能或者界面设计,以便更好地满足专业学习和实践操作的需要。 描述中还提到“请大家积极下载”,这可能意味着该学籍系统是一个开源项目,或者至少是一个允许公众访问的软件资源。由于开发者提出了“如有不足之处请大家多多包涵”,我们可以推断这个系统可能还处于测试或早期使用阶段,因此可能还不是完全成熟的版本,或者可能需要使用者反馈意见以便进行后续改进。 标签中的“C#的啊,大家注意,嘻嘻哈哈”表达了开发者轻松的态度和对C#语言的特定提及。这个标签可能是在一个非正式的交流环境中发布的,所以用词带有一定的随意性。尽管如此,它还是说明了该学籍系统是基于C#语言开发的,并提醒用户对这一点给予关注。 关于压缩包子文件的文件名称列表中,“学生成绩管理系统”直接指出了这个软件系统的主要功能之一,即管理学生的成绩。这通常包括录入成绩、查询成绩、统计分析成绩、成绩报告等功能。一个优秀的学生成绩管理系统可以让教师和学校管理人员更加高效地处理学生的成绩数据,同时也能让学生本人了解自己的学业进展。 综合以上信息,我们可以提炼出以下知识点: 1. C#语言:是一种面向对象的编程语言,适用于.NET框架,用于开发各种类型的应用程序。 2. 学籍系统:是管理学生基本信息、成绩、课程和学籍状态的软件应用系统,目的是实现学生信息的电子化管理。 3. 信息系统管理专业:该系统可能是针对信息系统管理专业的学生或教师的需求设计和开发的。 4. 开源项目或公众访问资源:鼓励用户下载使用,并接受用户的反馈和建议。 5. 学生成绩管理系统:是学籍系统的一个重要组成部分,专注于管理学生的成绩数据。 在开发一个C#设计的学籍系统时,开发者需要考虑的因素很多,比如系统的用户界面设计、数据库设计、数据安全、网络通信等。此外,系统还应该有良好的扩展性和易用性,以便未来可以根据用户反馈和新需求进行升级和优化。
recommend-type

特征值与特征向量速成课:理论精讲与7种高效算法

# 摘要 本文系统地介绍了特征值与特征向量的基本概念、理论深度剖析、高效特征值算法以及这些数学工具在实际问题中的应用。首先从定义与性质出发,详细解释了特征值与特征向量的
recommend-type

嵌入式Linux读写硬盘数据错误CF2 13473a 13433a 1342b2 13473a解决方案

<think>嗯,用户这次提出的问题很专业,是关于嵌入式Linux系统硬盘读写错误的解决方案。从错误代码CF2、13473a等来看,这应该是特定硬盘控制器或文件系统的错误码,需要结合硬件和系统环境分析。用户可能正在调试一个嵌入式设备,遇到了硬盘读写不稳定问题。这类错误通常涉及硬件连接、驱动兼容性、文件系统损坏等多个层面。用户提供的错误码格式看起来像十六进制值,可能是控制器寄存器状态或SCSI检测码。考虑到嵌入式系统的特殊性,需要从底层开始排查。首先应该检查物理连接,因为振动或接触不良在嵌入式环境中很常见。然后是驱动兼容性,嵌入式Linux常使用定制内核,驱动版本匹配很重要。另外,用户没有说明文