智能家居模拟系统的实现
// 智能家居模拟系统-文档
// 2015.12.14 by Huangtao
目前由以下组成:
由 STM32F103系列单片机 + RT-Thread嵌入式实时操作系统 +
串口转WIFI模块 + LED + LCD + L298 + 风扇 + 温度传感器
自定义通信协议:
1、'L' + 控制LED字符(0x11,0x10,0x21...)
2、'F' + 风扇控制符(0xf0,0xf1,0xf2...)
3、'TT',返回温度
手机APP端可以控制LED开关,获取温度,调节风扇转速。
/* application.c 2015.12.4 by Huangtao */ #include <board.h> #include <rtthread.h> #ifdef RT_USING_COMPONENTS_INIT #include <components.h> #endif /* RT_USING_COMPONENTS_INIT */ #ifdef RT_USING_DFS /* dfs filesystem:ELM filesystem init */ #include <dfs_elm.h> /* dfs Filesystem APIs */ #include <dfs_fs.h> #endif #ifdef RT_USING_RTGUI #include <rtgui/rtgui.h> #include <rtgui/rtgui_server.h> #include <rtgui/rtgui_system.h> #include <rtgui/driver.h> #include <rtgui/calibration.h> #endif // 我加入的 #include "led.h" #include "LCD5110.h" #include "ds18b20.h" #include "usart.h" #include "TIM3_PWM.h" // Thread ID static rt_thread_t led_id = RT_NULL; static rt_thread_t fan_id = RT_NULL; static rt_thread_t lcd5110_id = RT_NULL; static rt_thread_t ds18b20_id = RT_NULL; static rt_thread_t uart2_id = RT_NULL; #define CPU_USAGE_CALC_TICK 10 #define CPU_USAGE_LOOP 100 static rt_uint8_t cpu_usage_major = 0; //static cpu_usage_minor= 0; static rt_uint32_t total_count = 0; /* 自定义通信协议: ledControl: 'L'+ 0x10----led1 off 0x11----led1 on 0x20----led2 off 0x21----led2 on ... fanControl: 'F'+ 0xf0----fan off 0xf1----speed 1 0xf2----speed 2 ... */ static short temperature = 0; static char ledControl = 0; static char fanControl = 0; // 访问温度的互斥量 static rt_mutex_t mutexTemperature = RT_NULL; static rt_mutex_t mutexLed = RT_NULL; static rt_mutex_t mutexFan = RT_NULL; // stm32_usart2发送缓冲区 static char uart_tx_buffer[64] = "\nOpen uart2 OK.\0"; // stm32_usart2接收缓冲区 static char uart_rx_buffer[64]; // USART 接收消息结构 struct rx_msg { rt_device_t dev; rt_size_t size; }; // 用于接收消息的消息队列控制块 static rt_mq_t rx_mq; static struct rt_messagequeue my_rx_mq; // 消息队列中用到的放置消息的内存池 static char msg_pool[1024]; static void cpu_usage_idle_hook() { rt_tick_t tick; rt_uint32_t count; volatile rt_uint32_t loop; if (total_count == 0) { /* get total count */ rt_enter_critical(); tick = rt_tick_get(); while(rt_tick_get() - tick < CPU_USAGE_CALC_TICK) { total_count ++; loop = 0; while (loop < CPU_USAGE_LOOP) loop ++; } rt_exit_critical(); } count = 0; /* get CPU usage */ tick = rt_tick_get(); while (rt_tick_get() - tick < CPU_USAGE_CALC_TICK) { count ++; loop = 0; while (loop < CPU_USAGE_LOOP) loop ++; } /* calculate major and minor */ if (count < total_count) { count = total_count - count; cpu_usage_major = (count * 100) / total_count; //cpu_usage_minor = ((count * 100) % total_count) * 100 / total_count; } else { total_count = count; /* no CPU usage */ cpu_usage_major = 0; //cpu_usage_minor = 0; } } void cpu_usage_init() { /* set idle thread hook */ rt_thread_idle_sethook(cpu_usage_idle_hook); } /* // led ALIGN(RT_ALIGN_SIZE) static rt_uint8_t led_stack[ 512 ]; static struct rt_thread led_thread;*/ static void led_thread_entry(void* parameter) { rt_hw_led_init(); while (1) { rt_mutex_take(mutexLed, RT_WAITING_FOREVER); if(ledControl == 0x11) { // led1 on rt_hw_led_on(0); } else if(ledControl == 0x10) { // led1 off rt_hw_led_off(0); } else if(ledControl == 0x21) { // led2 on rt_hw_led_on(1); } else if(ledControl == 0x20) { // led2 off rt_hw_led_off(1); } rt_mutex_release(mutexLed); // 顺便清屏 //ClearScreen(); rt_thread_delay( 10 ); } } static void fan_thread_entry(void* parameter) { short Compare2Num = 0; TIM3_PWM_Init(900,5); // PWM频率=72000/5/900 while(1) { rt_mutex_take(mutexFan, RT_WAITING_FOREVER); switch(fanControl) { case 0xf0: Compare2Num=0; break; // 关 case 0xf1: Compare2Num=100; break; // 1档 case 0xf2: Compare2Num=150; break; // 2档 case 0xf3: Compare2Num=200; break; // ... case 0xf4: Compare2Num=250; break; case 0xf5: Compare2Num=300; break; case 0xf6: Compare2Num=350; break; case 0xf7: Compare2Num=400; break; case 0xf8: Compare2Num=450; break; case 0xf9: Compare2Num=500; break; case 0xfa: Compare2Num=600; break; case 0xfb: Compare2Num=700; break; case 0xfc: Compare2Num=800; break; case 0xfd: Compare2Num=900; break; // 13档 default: break; } rt_mutex_release(mutexFan); TIM_SetCompare2(TIM3, Compare2Num); rt_thread_delay(10); } } // lcd5110 static void lcd5110_thread_entry(void* parameter) { LcdInit(); while(1) { DispString(15,0,"RT-Thread"); DispString(0,1,"CPU:"); DispNum(30,1,cpu_usage_major); DispChar(45,1,'%'); rt_thread_delay( 5 ); } } // ds18b20 static void ds18b20_thread_entry(void* parameter) { short showTemp; //rt_err_t result; while(DS18B20_Init()); while(1) { DispString(0,3,"Temp: "); rt_mutex_take(mutexTemperature, RT_WAITING_FOREVER); temperature = DS18B20_Get_Temp(); showTemp = temperature; rt_mutex_release(mutexTemperature); if(showTemp<0) { DispChar(40,3,'-'); showTemp=-showTemp; } else DispChar(40,3,' '); DispNum(48,3,((u16)showTemp)/10); //显示正数部分 DispChar(60,3,'.'); DispNum(67,3,((u16)showTemp)%10); //显示小数部分 rt_thread_delay( 5 ); } } // uart2 //=============================================== // 数据到达回调函数 // rt_err_t(*)(rt_device_t dev, rt_size_t size) rt_err_t uart_input(rt_device_t dev, rt_size_t size) { struct rx_msg msg; msg.dev = dev; msg.size = size; if(size >=2) { // 发送消息到消息队列中 rt_mq_send(rx_mq, &msg, sizeof(struct rx_msg)); } return RT_EOK; } static void uart2_thread_entry(void* parameter) { rt_err_t result = RT_EOK; struct rx_msg msg; rt_device_t stm32_uart2; rt_uint32_t rx_length; // 根据注册名查找设备 stm32_uart2 = rt_device_find("uart2"); if (stm32_uart2 != RT_NULL) { // 初始化设备 rt_device_init(stm32_uart2); // 设置回调函数(当设备接收到数据执行) rt_device_set_rx_indicate(stm32_uart2, uart_input); // 打开设备 rt_device_open(stm32_uart2, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM); } rt_device_write(stm32_uart2, 0, &uart_tx_buffer[0], 18); while(1) { // 从消息队列中读取消息, RT_WAITING_FOREVER result = rt_mq_recv(rx_mq, &msg, sizeof(struct rx_msg), RT_WAITING_FOREVER); // 成功收到消息 if(result == RT_EOK) { rx_length = (sizeof(uart_rx_buffer) - 1) > msg.size ? msg.size : sizeof(uart_rx_buffer) - 1; // 读取消息 rx_length = rt_device_read(msg.dev, 0, &uart_rx_buffer[0], rx_length); uart_rx_buffer[rx_length] = '\0'; // 'F' + fanControl if(uart_rx_buffer[0] == 0x46) { rt_mutex_take(mutexFan, RT_WAITING_FOREVER); fanControl = uart_rx_buffer[1]; rt_mutex_release(mutexFan); } // 'L' + ledControl else if(uart_rx_buffer[0] == 0x4c) { rt_mutex_take(mutexLed, RT_WAITING_FOREVER); ledControl = uart_rx_buffer[1]; rt_mutex_release(mutexLed); } // 收到'T',则发送温度 else if(uart_rx_buffer[0] == 0x54) { rt_mutex_take(mutexTemperature, RT_WAITING_FOREVER); uart_tx_buffer[0] = temperature & 0xff; uart_tx_buffer[1] = (temperature >> 8) & 0xff; uart_tx_buffer[2] = '\0'; rt_mutex_release(mutexTemperature); rt_device_write(stm32_uart2, 0, &uart_tx_buffer[0], 2); } // 回显观察 //rt_device_write(stm32_uart2, 0, &uart_rx_buffer[0], rx_length); } //rt_thread_delay( 5 ); } } void rt_init_thread_entry(void* parameter) { #ifdef RT_USING_COMPONENTS_INIT /* initialization RT-Thread Components */ rt_components_init(); #endif #ifdef RT_USING_FINSH finsh_set_device(RT_CONSOLE_DEVICE_NAME); #endif /* RT_USING_FINSH */ /* Filesystem Initialization */ #if defined(RT_USING_DFS) && defined(RT_USING_DFS_ELMFAT) /* mount sd card fat partition 1 as root directory */ if (dfs_mount("sd0", "/", "elm", 0, 0) == 0) { rt_kprintf("File System initialized!\n"); } else rt_kprintf("File System initialzation failed!\n"); #endif /* RT_USING_DFS */ #ifdef RT_USING_RTGUI { extern void rt_hw_lcd_init(); extern void rtgui_touch_hw_init(void); rt_device_t lcd; /* init lcd */ rt_hw_lcd_init(); /* init touch panel */ rtgui_touch_hw_init(); /* find lcd device */ lcd = rt_device_find("lcd"); /* set lcd device as rtgui graphic driver */ rtgui_graphic_set_device(lcd); #ifndef RT_USING_COMPONENTS_INIT /* init rtgui system server */ rtgui_system_server_init(); #endif calibration_set_restore(cali_setup); calibration_set_after(cali_store); calibration_init(); } #endif /* #ifdef RT_USING_RTGUI */ } // 创建线程和初始化 //============================================================ int rt_application_init(void) { rt_thread_t init_thread; // 初始化消息队列 rt_mq_init(&my_rx_mq, "mqt", &msg_pool[0], sizeof(struct rx_msg), sizeof(msg_pool), RT_IPC_FLAG_FIFO); rx_mq = &my_rx_mq; // 创建互斥锁 mutexTemperature = rt_mutex_create("mutexTemperature", RT_IPC_FLAG_FIFO); if (mutexTemperature == RT_NULL) { return 0; } mutexLed = rt_mutex_create("mutexLed", RT_IPC_FLAG_FIFO); if (mutexLed == RT_NULL) { return 0; } mutexFan = rt_mutex_create("mutexFan", RT_IPC_FLAG_FIFO); if (mutexFan == RT_NULL) { return 0; } /*rt_err_t result; // 静态创建 led 线程 result = rt_thread_init(&led_thread, // 线程控制块内存地址 "led", // 线程名称 led_thread_entry, // 线程入口入口函数 RT_NULL, // 线程入口入口函数参数 (rt_uint8_t*)&led_stack[0], // 线程栈起始地址 sizeof(led_stack), // 线程栈大小 20, // 线程优先级 5); // 线程时间片大小 if (result == RT_EOK) { rt_thread_startup(&led_thread); }*/ // 动态创建 led 线程 led_id = rt_thread_create("led", // 线程名称 led_thread_entry, // 线程入口入口函数 RT_NULL, // 线程入口入口函数参数 512, // 线程栈大小 21, // 线程优先级 10); // 线程时间片大小 // 如果获得线程控制块,启动这个线程 if (led_id != RT_NULL) rt_thread_startup(led_id); // 动态创建 fan 线程 fan_id = rt_thread_create("fan", // 线程名称 fan_thread_entry, // 线程入口入口函数 RT_NULL, // 线程入口入口函数参数 1024, // 线程栈大小 20, // 线程优先级 10); // 线程时间片大小 // 如果获得线程控制块,启动这个线程 if (fan_id != RT_NULL) rt_thread_startup(fan_id); // 动态创建 lcd5110 线程 lcd5110_id = rt_thread_create("lcd5110", // 线程名称 lcd5110_thread_entry, // 线程入口入口函数 RT_NULL, // 线程入口入口函数参数 512, // 线程栈大小 20, // 线程优先级 20); // 线程时间片大小 if (lcd5110_id != RT_NULL) rt_thread_startup(lcd5110_id); // 动态创建 ds18b20 线程 ds18b20_id = rt_thread_create("ds18b20", // 线程名称 ds18b20_thread_entry, // 线程入口入口函数 RT_NULL, // 线程入口入口函数参数 1024, // 线程栈大小 19, // 线程优先级 20); // 线程时间片大小 if (ds18b20_id != RT_NULL) rt_thread_startup(ds18b20_id); // 动态创建 usart2 线程 uart2_id = rt_thread_create("uart2", // 线程名称 uart2_thread_entry, // 线程入口入口函数 RT_NULL, // 线程入口入口函数参数 2048, // 线程栈大小 19, // 线程优先级 15); // 线程时间片大小 if (uart2_id != RT_NULL) rt_thread_startup(uart2_id); // CPU % cpu_usage_init(); #if (RT_THREAD_PRIORITY_MAX == 32) init_thread = rt_thread_create("init", rt_init_thread_entry, RT_NULL, 2048, 8, 20); #else init_thread = rt_thread_create("init", rt_init_thread_entry, RT_NULL, 2048, 80, 20); #endif if (init_thread != RT_NULL) rt_thread_startup(init_thread); return 0; }