完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
实现原理
以下会分别介绍下位机中关键部分的实现威廉希尔官方网站 ,包括μC/OS-II多任务实现、串口数据的读取、对数据的解析等。 下位机硬件资源介绍
μC/OS-II是一个可裁剪的、可固话的、可移植的、抢占式实时多任务系统内核,适用于多种微处理器和微控制器,能够移植到超过100多种微处理器应用开发中。本次下位机中就移植了这样一个小型的嵌入式操作系统,使得整个系统显示十分的流畅,而且也很好管理。 μC/OS-II的移植这里就不说了,网上有好多的介绍,其中正点原子和野火的讲的都比较详细,可以去看看,首先说明,我的这个工程也是参考他们的。一下是我的整个工程的结构,整体上还算比较详细的: 通过代码可以很清晰的看出来各个传感器的 驱动、数据的读取等细节,这里主要说说系统多的任务的实现。 主函数开始后进行了一些列的初始化操作,随后初始化了μC/OS-II系统,并且创建了一个开始任务: 各个模块初始化操作: delay_init(); //延时初始化 uart_init(115200); //串口1初始化 uart3_init(115200); //串口3初始化(连接ZigBee接口) JTAG_Set(JTAG_SWD_DISABLE); //关闭JTAG接口 NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 BEEP_Init(); //初始化蜂鸣器接口 LED_Init(); //初始化与LED连接的硬件接口 Scan_Key_Configuration(); //初始化按键接口 STEP_MOTOR_Start(); //初始化步进电机接口 Lsens_Init(); //初始化光敏传感器接口 MQ_2_Configuration(); //初始化烟雾传感器接口 HC_SR501_GPIO_Configuration(); //初始化红外热释点接口 STEP_MOTOR_Configuration(); //初始化步进电机接口 while(DHT11_Init()) //DHT11初始化,检测不到会卡死在这里 { #if FLAG_SHOW_VALUE printf("rnDHT11 Init Error"); #endif delay_ms(600); } #if FLAG_SHOW_VALUE printf("DHT11 OKrn"); #endif while(DS18B20_Init()) //初始化DS18B20,检测不到会卡死在这里不断检测 { printf("rnDS18B20 Init Error"); delay_ms(600); } printf("DS18B20 Init OKrn"); 创建开始任务: OSInit(); OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//创建起始任务 OSStart(); 开始任务创建成功后便会在开始任务里边进行其他任务的初始化操作: //开始任务 void start_task(void *pdata) { OS_CPU_SR cpu_sr = 0; pdata = pdata; OSStatInit(); //初始化统计任务.这里会延时1秒钟左右 OS_ENTER_CRITICAL(); //进入临界区(无法被中断打断) //红外热释任务 OSTaskCreate(hc_sr501_task,(void *)0, (OS_STK*)&HC_SR501_TASK_STK[HC_SR501_STK_SIZE-1],HC_SR501_TASK_PRIO); //创建温湿度任务 OSTaskCreate(dht11_task,(void *)0, (OS_STK*)&DHT11_TASK_STK[DHT11_STK_SIZE - 1],DHT11_TASK_PRIO); //创建温度任务 OSTaskCreate(ds18b20_task,(void *)0, (OS_STK*)&DS18B20_TASK_STK[DS18B20_STK_SIZE-1],DS18B20_TASK_PRIO); //创建光敏检测任务 OSTaskCreate(telesky_task,(void *)0, (OS_STK*)&TELESKY_TASK_STK[TELESKY_STK_SIZE-1],TELESKY_TASK_PRIO); //创建烟雾检测任务 OSTaskCreate(mq_2_task,(void *)0, (OS_STK*)&MQ_2_TASK_STK[MQ_2_STK_SIZE-1],MQ_2_TASK_PRIO); //创建串口3任务,用来进行和上位机通讯 OSTaskCreate(uart3_task,(void *)0, (OS_STK*)&UART3_TASK_STK[UART3_STK_SIZE-1],UART3_TASK_PRIO); //创建蜂鸣器任务 OSTaskCreate(beep_task,(void *)0, (OS_STK*)&BEEP_TASK_STK[BEEP_STK_SIZE-1],BEEP_TASK_PRIO); //按键扫描任务 OSTaskCreate(key_task,(void *)0, (OS_STK*)&KEY_TASK_STK[KEY_STK_SIZE-1],KEY_TASK_PRIO); //创建步进电机任务 OSTaskCreate(step_motor_task,(void *)0, (OS_STK*)&STEP_MOTOR_TASK_STK[STEP_MOTOR_STK_SIZE-1],STEP_MOTOR_TASK_PRIO); OSTaskSuspend(START_TASK_PRIO); //挂起起始任务. OS_EXIT_CRITICAL(); //退出临界区(可以被中断打断) } 可以很清楚的看到,开始任务里边创建了多个任务,接着,各个任务创建成功后边会挂起任务,退出临界区,开始各个任务的轮训操作。 上面各个任务创建时,都指定了任务优先级,堆栈大小等信息。在app.h文件中可以看到: //开始任务 #define START_TASK_PRIO 10 //开始任务的优先级设置为最低 #define START_STK_SIZE 64 //设置任务堆栈大小 OS_STK START_TASK_STK[START_STK_SIZE]; //创建任务堆栈空间 void start_task(void *pdata); //任务函数接口 //创建步进电机任务 #define STEP_MOTOR_TASK_PRIO 11 #define STEP_MOTOR_STK_SIZE 64 OS_STK STEP_MOTOR_TASK_STK[STEP_MOTOR_STK_SIZE]; void step_motor_task(void *pdata); // //按键扫描任务 // #define KEY_TASK_PRIO 10 设置任务优先级 #define KEY_STK_SIZE 90 //设置任务堆栈大小 OS_STK KEY_TASK_STK[KEY_STK_SIZE]; //创建任务堆栈空间 void key_task(void *pdata); //任务函数接口 //蜂鸣器任务--根据各个传感器数据,进行报警 #define BEEP_TASK_PRIO 9 #define BEEP_STK_SIZE 64 OS_STK BEEP_TASK_STK[BEEP_STK_SIZE]; void beep_task(void *pdata); // //人体感应模块 任务 #define HC_SR501_TASK_PRIO 8 #define HC_SR501_STK_SIZE 64 OS_STK HC_SR501_TASK_STK[HC_SR501_STK_SIZE]; void hc_sr501_task(void *pdata); //光敏传感器采集任务 #define TELESKY_TASK_PRIO 7 //设置任务优先级 #define TELESKY_STK_SIZE 64 //设置任务堆栈大小 OS_STK TELESKY_TASK_STK[TELESKY_STK_SIZE]; //创建任务堆栈空间 void telesky_task(void *pdata); //任务函数接口 //DHT11任务(温湿度传感器) #define DHT11_TASK_PRIO 6 //设置任务优先级 #define DHT11_STK_SIZE 64 //设置任务堆栈大小 OS_STK DHT11_TASK_STK[DHT11_STK_SIZE]; //创建任务堆栈空间 void dht11_task(void *pdata); //任务函数接口 //MQ-2任务(烟雾传感器) #define MQ_2_TASK_PRIO 5 //设置任务优先级 #define MQ_2_STK_SIZE 90 //设置任务堆栈大小 OS_STK MQ_2_TASK_STK[MQ_2_STK_SIZE]; //创建任务堆栈空间 void mq_2_task(void *pdata); //任务函数接口 //DS18B20任务 #define DS18B20_TASK_PRIO 4 #define DS18B20_STK_SIZE 64 OS_STK DS18B20_TASK_STK[DS18B20_STK_SIZE]; void ds18b20_task(void *pdata); //串口发送数据任务(用来想上位机 实时 传输输出) #define UART3_TASK_PRIO 3 #define UART3_STK_SIZE 90 OS_STK UART3_TASK_STK[UART3_STK_SIZE]; void uart3_task(void *pdata); 任务的优先级决定了任务在被打断时执行的顺序,优先级越高,越有优先权。 串口数据的读取 在单片机开发过程中串口的操作可以算是最普通也是最基础的操作了,好多东西都是需要通过串口进行输出,这样可以对程序执行过程中的一些中间数据进行输出。这里主要说说串口数据的读取。 数据的读取使用中断的方式进行交互,这样效率很高。这里执行看核心代码即可: void recv_zigbee_msg(u8 Res) { if(Res == END_RESD_MSG) { FLAG_ZIGBEE_RECV_BEGIN = 0; USART3_RX_BUF[USART3_RX_STA++&0X3FFF] = Res; cpynbyte2buffer(USART3_RX_BUF, USART3_RX_STA); USART3_RX_STA = 0; memset(USART3_RX_BUF, 0, sizeof(USART3_RX_BUF)); }else if(Res == BGN_RESD_MSG || FLAG_ZIGBEE_RECV_BEGIN) { FLAG_ZIGBEE_RECV_BEGIN = 1; USART3_RX_BUF[USART3_RX_STA++&0X3FFF] = Res; }else { FLAG_ZIGBEE_RECV_BEGIN = 0; USART3_RX_STA = 0; memset(USART3_RX_BUF, 0, sizeof(USART3_RX_BUF)); } } 这里接收数据时对帧头进行了一个简单的判断,正确后接着接收,碰到帧尾后将数据拷贝到了一个缓冲区中,然后清空接收缓冲。整个过程就这么简单。 数据的打包和解析操作 数据解析 前一部分介绍了数据的接收,这里再说说对数据的解析。从上面的代码中可以看出来有个函数:cpynbyte2buffer(),该函数是吸纳对数据的解析操作,如下所示: void cpynbyte2buffer(u8 *data, u8 len) { int i = 0; u8 data_postion = 0; protocol recvMsg; if (BGN_RESD_MSG == data[data_postion++]) { printf("beginrn"); recvMsg.potocol_len = data[data_postion++]; recvMsg.device = data[data_postion++]; recvMsg.device_cmd = data[data_postion++]; recvMsg.data_len = data[data_postion++]; if (recvMsg.data_len > 0) { recvMsg.data = (u8 *)malloc(sizeof(u8)*recvMsg.data_len); for (i = 0;i < recvMsg.data_len ;i++) { recvMsg.data = data[data_postion++]; } } if (data[data_postion] == END_RESD_MSG) { printf("endrn"); recv_data(&recvMsg); } } } 在上面对数据结构体进行了赋值后便开始了整整的数据或者命令的执行,如 recv_data(protocol *protocol)所示: void recv_data(protocol *protocol) { switch(protocol->device) { case MODULE_BEEP: exec_module_beep(protocol); break; case MODULE_BED_ROOM_LED_LEFT: exec_module_led(protocol); break; case MODULE_BED_ROOM_LED_RIGHT: exec_module_led(protocol); break; case MODULE_PARLOUR_LED_MAIN: exec_module_led(protocol); break; case MODULE_PARLOUR_LED_TOP: exec_module_led(protocol); break; case MODULE_PARLOUR_LED_HELP: exec_module_led(protocol); break; case MODULE_KITCHIN_LED: exec_module_led(protocol); break; //case MODULE_CURTAIN: exec_module_curtain(protocol); break; case MODULE_ALL_LED: exec_module_all_led(protocol); break; //case MODULE_LEAVE_HOME: exec_module_leave_home(protocol); break; case MODULE_GO_HOME: exec_module_go_home(protocol); break; case MODULE_SMOKE: exec_module_change_smoke_value(protocol); break; case MODULE_DS18B20: exec_module_change_parlour_temp(protocol);break; case MODULE_DHT11_HUM: exec_module_change_parlour_hum(protocol); break; default: break; } } 数据打包发送 数据发送任务函数: pack_send_data(MODULE_DS18B20, PROTOCOL_FULL_DATA, DATA_SIZE,parlour_temp_data); //客厅温度 delay_ms(400); pack_send_data(MODULE_DHT11_TEMP, PROTOCOL_FULL_DATA, DATA_SIZE, bed_tempture_data);//卧室温度 delay_ms(400); pack_send_data(MODULE_DHT11_HUM,PROTOCOL_FULL_DATA,DATA_SIZE,humidity_data); //客厅湿度 delay_ms(400); pack_send_data(MODULE_SMOKE,PROTOCOL_FULL_DATA,DATA_SIZE,kitchen_smoke_data); //厨房浓度值 delay_ms(400); 上面是数据发送任务里调用的发送函数,该函数中对各个传感器采集到的数据进行了打包并发送操作。可以看打包发送函数: /* * @function pack_send_data * @input * @output * @brief 通讯协议功能的实现. * 本文件实现了数据包的发送和接受,以及根据数据类型执行对应的函数 */ void pack_send_data(u8 drive, u8 drive_cmd, u8 data_len, u8 *data) { protocol Msg; Msg.send_begin = BGN_RESD_MSG; //帧头 # //若数据长度 > 0,即有数据 if(data_len > 0) { Msg.potocol_len = PROTOCOL_BASIC_SIZE + data_len - 1; }else { Msg.potocol_len = PROTOCOL_BASIC_SIZE; } //填充数据结构体 Msg.device = drive; Msg.device_cmd = drive_cmd; Msg.data_len = data_len; Msg.data = data; Msg.send_end = END_RESD_MSG; //帧尾* //发送数据 send_data(&Msg); } 这里列出来核心代码,具体实现代码请看工程。打包发送函数中主要做了2件事情:一:对数据成员初始化,二:判断一帧数据的大小!数据大小值很重要的,这在数据解析过程可需要用到。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1786 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1622 浏览 1 评论
1089 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
730 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1680 浏览 2 评论
1942浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
739浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
576浏览 3评论
598浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
560浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-25 13:03 , Processed in 0.968732 second(s), Total 76, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号