搜索
返回列表 发新帖本帖赏金 101.00元(功能说明)我要提问

[STM32] 不会还有人不知道吧?养宠还用手?看看涂鸦怎么说->

[复制链接]
1444|9
 楼主 | 2021-3-25 14:12 | 显示全部楼层 |阅读模式
本帖最后由 呐咯密密 于 2021-4-5 14:18 编辑

#申请原创#       @21小跑堂
去年疫情突发,全国很多地区封城,封小区,让原本备受宠爱的主子与铲屎官异地分离。遇到有准备的铲屎官,主子们还能勉强度日,那些没有准备的主子只能靠吃猫砂,吃垃圾度日,甚至有些小可怜被活活饿死。
      疫情缓解后,为了避免这样的事件再次发生,也为了解放懒惰的铲屎官,于是自动猫砂盆,自动喂食器,自动喂水器的需求不断提升。有数据显示,疫情后自动猫砂盆增长879%,自动喂水器增长120%,自动喂食器增长也超一倍。毕竟主子是家里的老大,要吃好喝好还要拉好。
此次DIY自动投食器由涂鸦智能开展的【宠物喂食器】实战营策划,并提供了涂鸦三明治开发套件,其中包括:
涂鸦三明治 Wi-Fi MCU 通信板*1
54938605c3dfdbb6ad.png
涂鸦三明治H桥直流电机驱动功能板*1
94096605c0c0ab1658.png
涂鸦三明治直流供电电源板*1。
77647605c0c2f32733.png
妥妥三大件,用户需要自行准备MCU控制板和电机等组件。
该WiFi模组出厂默认为透传模式,只负责数据转发,不负责数据处理,所以我们只需要准备MCU用于数据处理和外设控制。
涂鸦IOT平台
1.前往涂鸦智能开发平台注册开发者账号
52710605c0d89210ff.png
2.点击创建产品
20201605c0dbddb20a.png
在小家电品类里找到【宠物喂食器】
77217605c0dfca863c.png 87816605c0e071d7d8.png
3.使用MCU SDK方案,完善产品信息
84300605c0e5144f6d.png 33582605c0e97a9135.png
4.创建产品后可添加标准功能,自行选择
35142605c0ed79b00c.png
5.硬件开发如下配置
56194605c0f7c6dd40.png
以上步奏更加具体配置可参考涂鸦IOT平台产品创建流程
产品创建完成后下载开发资料,建议全部下载,其中MCU SDK的内容会根据你所选择的标准功能不同而不同,为了方便可在选择功能时尽可能多的考虑到需要配置的功能,当然,即使你一个不选,SDK也开放了各个功能的函数,只是被屏蔽,可自行放开。
功能调试:
MCU对接方案通信原理图:
70103605c2923316d0.png
1.WiFi模组调试
上一步最终下载的文件如下图,第一步我们打开涂鸦调试助手
70775605c114d9d4ae.png 61517605c115679a3a.png
将WiFi的通信板的串口1接到usb-ttl上,接到电脑,一定是串口1,串口0是查看模组本身的logo的,打开涂鸦调试助手。选择MCU模拟,此时调试助手就相当于是MCU,可以与WiFi模组通信,可用此来调试WiFi模组。选择好串口,波特率默认9600.功能点调试文件选择之前下载的json文件。初始化配置保持默认,点击开始调试。如收到以下数据说明模组与助手连接正常,可以开始调试。
94474605c1522eb5e6.png
此时我们下载涂鸦智能APP,注册后选择添加设备,在小家电里面找到宠物喂食器,选择2.4G的WiFi网络。输入密码。点击下一步
88525605c15d0df414.png
此时在模组调试助手点击smart配网,手机点击下一步
54480605c1616d7828.png 96078605c16db3f585.png 21796605c16ee9e9d4.png
配网成功后会在手机APP和调试助手同时看到相应信息。连接成功后会定时发送心跳包保持连接。
92612605c164e62a78.png
至此WiFi模组配网完成,改配网信息会保存在WiFi模组内部,下次上电会自动连接该网络。如果更换网络环境需要重置后再次配网。
此时可在DP CMD里面测试相关DP点的数据上报,观察有无数据的上报下发。
2.MCU调试
WiFi模组调试完成之后我们需要调试我们的主控,也就是MCU,在我这里就是STM32F103。
在进行MCU调试之前我们需要先进行SDK的移植,将之前下载的SDK移植到我们的STM32项目中。
(1),基础工程创建
移植前,我们需要准备一个空的工程,工程中只需要添加一个串口驱动便可。
  1. #ifndef __USART_H
  2. #define        __USART_H


  3. #include "stm32f10x.h"
  4. #include <stdio.h>

  5. // 串口1-USART1
  6. #define  DEBUG_USARTx                   USART1
  7. #define  DEBUG_USART_CLK                RCC_APB2Periph_USART1
  8. #define  DEBUG_USART_APBxClkCmd         RCC_APB2PeriphClockCmd
  9. #define  DEBUG_USART_BAUDRATE           9600

  10. // USART GPIO 引脚宏定义
  11. #define  DEBUG_USART_GPIO_CLK           (RCC_APB2Periph_GPIOA)
  12. #define  DEBUG_USART_GPIO_APBxClkCmd    RCC_APB2PeriphClockCmd
  13.    
  14. #define  DEBUG_USART_TX_GPIO_PORT         GPIOA   
  15. #define  DEBUG_USART_TX_GPIO_PIN          GPIO_Pin_9
  16. #define  DEBUG_USART_RX_GPIO_PORT       GPIOA
  17. #define  DEBUG_USART_RX_GPIO_PIN        GPIO_Pin_10

  18. #define  DEBUG_USART_IRQ                USART1_IRQn
  19. #define  DEBUG_USART_IRQHandler         USART1_IRQHandler


  20. void USART_Config(void);
  21. void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);
  22. #endif /* __USART_H */
复制代码
先在串口的.h文件中进行宏定义。然后开始USART1的初始化,串口接收中断的初始化。
  1. /**
  2.   * [url=home.php?mod=space&uid=247401]@brief[/url]  配置嵌套向量中断控制器NVIC
  3.   * @param  无
  4.   * @retval 无
  5.   */
  6. static void NVIC_Configuration(void)
  7. {
  8.   NVIC_InitTypeDef NVIC_InitStructure;
  9.   
  10.   /* 嵌套向量中断控制器组选择 */
  11.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  12.   
  13.   /* 配置USART为中断源 */
  14.   NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
  15.   /* 抢断优先级*/
  16.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  17.   /* 子优先级 */
  18.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  19.   /* 使能中断 */
  20.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  21.   /* 初始化配置NVIC */
  22.   NVIC_Init(&NVIC_InitStructure);
  23. }

  24. /**
  25.   * [url=home.php?mod=space&uid=247401]@brief[/url]  USART GPIO 配置,工作参数配置
  26.   * @param  无
  27.   * @retval 无
  28.   */
  29. void USART_Config(void)
  30. {
  31.         GPIO_InitTypeDef GPIO_InitStructure;
  32.         USART_InitTypeDef USART_InitStructure;

  33.         // 打开串口GPIO的时钟
  34.         DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
  35.         
  36.         // 打开串口外设的时钟
  37.         DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);

  38.         // 将USART Tx的GPIO配置为推挽复用模式
  39.         GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
  40.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  41.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  42.         GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);

  43.   // 将USART Rx的GPIO配置为浮空输入模式
  44.         GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
  45.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  46.         GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
  47.         
  48.         // 配置串口的工作参数
  49.         // 配置波特率
  50.         USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
  51.         // 配置 针数据字长
  52.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  53.         // 配置停止位
  54.         USART_InitStructure.USART_StopBits = USART_StopBits_1;
  55.         // 配置校验位
  56.         USART_InitStructure.USART_Parity = USART_Parity_No ;
  57.         // 配置硬件流控制
  58.         USART_InitStructure.USART_HardwareFlowControl =
  59.         USART_HardwareFlowControl_None;
  60.         // 配置工作模式,收发一起
  61.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  62.         // 完成串口的初始化配置
  63.         USART_Init(DEBUG_USARTx, &USART_InitStructure);
  64.         
  65.         // 串口中断优先级配置
  66.         NVIC_Configuration();
  67.         
  68.         // 使能串口接收中断
  69.         USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);        
  70.         
  71.         // 使能串口
  72.         USART_Cmd(DEBUG_USARTx, ENABLE);            
  73. }
复制代码
写一个发送单字节函数,此函数必须,用于向WiFi模组发送数据。
  1. void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
  2. {
  3.         /* 发送一个字节数据到USART */
  4.         USART_SendData(pUSARTx,ch);
  5.                
  6.         /* 等待发送数据寄存器为空 */
  7.         while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);        
  8. }
复制代码
(2)移植SDK
基础工程搭建完成后将SDK放入工程
83612605c20849b1e9.png

concrol.c是我自己添加的文件,忽略。此时编译会疯狂报错,因为下载的SDK中有很多未屏蔽的注释,都是很重要的注释,可能怕我们找不到关键点吧。
比如:
45774605c1fb2b9ffb.png
此处我们按照要求将串口的单字节发送函数填入
52353605c1ff52b901.png
不好意思,顺序乱了,第一步从这里开始:
确认 protocol.h 宏定义
1.定义 PIDPRODUCT_KEY 为产品 PID 宏定义。PID 即产品 ID, 为每个产品的唯一标识,可在 IoT 平台的产品详情页面获取。
98617605c212bb4e2b.png
  1. #define PRODUCT_KEY "gktqnpciyofn****"    //开发平台创建产品后生成的16位字符产品唯一标识
复制代码
2.定义 Wi-Fi 模块工作模式。CONFIG_MODE 为配网方式,支持默认模式(AP 和 SmartConfig 互相切换)、安全模式、防误触模式。建议选择防误触模式。
3.定义模块工作方式(必选)
如果配网按键和 LED 接在 MCU 端,即选择模块和 MCU 配合处理工作模式(常用),保持 WIFI_CONTROL_SELF_MODE 宏定义处于被注释状态
  1. //#define         WIFI_CONTROL_SELF_MODE                       //Wi-Fi 自处理按键及LED指示灯,如为MCU外接按键/LED指示灯请关闭该宏
复制代码


如果配网指示灯和按键是接在 Wi-Fi 模块上的,即选择模块自处理工作模式,开启 WIFI_CONTROL_SELF_MODE 宏定义,然后根据实际的硬件连接,将指示灯和按键所连接的 GPIO 脚位填入下面两个宏定义。
  1. #ifdef          WIFI_CONTROL_SELF_MODE                        //模块自处理
  2.     #define     WF_STATE_KEY            14                    //Wi-Fi 模块状态指示按键,请根据实际 GPIO 管脚设置
  3.     #define     WF_RESERT_KEY           0                     //Wi-Fi 模块重置按键,请根据实际 GPIO 管脚设置
  4. #endif
复制代码

这三项是很重要的配置,因为篇幅原因,其他配置不再此赘述,代码中均有注释。可自行开放。
移植 protocol.c 文件及函数调用
  • 将wifi.h 文件保存至存放 Wi-Fi 相关文件的文件夹中,例如 main.c文件夹而我是创建了一个WiFi文件夹,WiFi.c只是引用了wifi.h这个头文件,其他为空。

  • 在 MCU 串口及其他外设初始化后调用 mcu_api.c 文件中的 wifi_protocol_init() 函数。

  • 将 MCU 串口单字节发送函数填入 protocol.c 文件中 uart_transmit_output 函数内,并删除 #error此步骤在上文已介绍。不赘述。

  • 在串口接收中断服务函数里面调用 mcu_api.c 文件内的 uart_receive_input 函数,并将接收到的字符作为参数传入。示例如下:

    1. // 串口中断服务函数
    2. void DEBUG_USART_IRQHandler(void)
    3. {
    4.   uint8_t ucTemp;
    5.         if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET)
    6.         {               
    7.                 ucTemp = USART_ReceiveData(DEBUG_USARTx);
    8.                 uart_receive_input(ucTemp);   
    9.         }        
    10.         USART_ClearFlag(USART1,USART_FLAG_RXNE);        
    11. }
    复制代码

  • 在主函数的while(1) 循环后调用 mcu_api.c 文件内的 wifi_uart_service() 函数。该函数用于wifi串口数据处理服务,同时维持心跳。此函数无需任何判断条件,直接调用。在使用该函数时最好不要关闭总中断或串口中断,防止数据丢失,如必要,尽可能短的时间关闭。                                                                                                                         59663605c24e141063.png
至此,SDK移植便已完成,此时可将单片机的串口接到电脑进行调试。此时调试助手选择模组模拟。

为了便于观察,我们在protocol.c文件中将all_data_update() 函数中的所有DP点上传函数打开,默认为0。
62124605c26b251abd.png
此时MCU接到调试助手,打开串口,添加DP点文件,启动调试,便会看到所有DP点的上报。
10279605c277ea1611.png
进入DP CMD添加一个开启小夜灯的指令并下发,便可看到模组成功接收,说明MCU的SDK移植成功。
28673605c27e6cac83.png
到此为止,一个完整的自动喂食器的MCU工程便已搭建完成,后续我们只需要解析wifi模组下发的消息,并进行相应的外设控制便可。当然,每次MCU完成动作后也要上传数据给模组。完成服务器和手机APP端的数据刷新。
这些功能会以跟帖形式发表。源代码等也会在文章最后进行附录,同时也会上传git.感谢大佬们捧场。
游客,如果您要查看本帖隐藏内容请回复







使用特权

评论回复

打赏榜单

21小跑堂 打赏了 100.00 元 2021-04-02
理由:恭喜通过原创奖审核!请多多加油哦!

巧克力娃娃 打赏了 1.00 元 2021-04-01
理由:先马后看

 楼主 | 2021-3-25 17:19 | 显示全部楼层
本帖最后由 呐咯密密 于 2021-4-1 15:21 编辑

完善功能
一、添加配网功能及指示灯函数
前面的准备工作完成后我们需要添加功能,从最重要的配网开始吧,总不能每次使用都插上电脑用助手配网呀,那多不方便,一键上云才是王道。其实语音也可以,嘻嘻嘻,而且音色也不错,是个萌妹子的声音。跑题了,语音功能容后考虑,因为我觉得加个语音功能我家的主子会炸毛,可能会有吃饭恐惧症。
配网有两种模式AP配网和smart配网,这里仅介绍smart类型。
配网指令有两个函数可以实现:mcu_reset_wifi() mcu_set_wifi_mode()。通常在按键触发配网后,在按键处理函数中调用。

mcu_reset_wifi()调用后复位 Wi-Fi 模组,复位后之前的配网信息全部清除mcu_reset_wifi() 每调用一次,Wi-Fi 模块即在 AP 和 Smart 之间切换一次配网模式。

mcu_set_wifi_mode()参数为SMART_CONFIG和AP_CONFIG。调用后清除配网信息,进入 Smart 模式或者 AP 模式。

通常在 while(1) 调用 mcu_get_wifi_work_state() 函数获取 Wi-Fi 状态。根据 Wi-Fi 状态,写入相应闪灯的模式。

通过switch()判断进入何种状态,状态可选参数如下:

所以,我们先开始写按键的驱动以及外部中断:

  1. //按键初始化函数
  2. void KEY_Init(void) //IO初始化
  3. {
  4.          GPIO_InitTypeDef GPIO_InitStructure;

  5.          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能PORTA,PORTE时钟

  6.         //初始化 WK_UP-->GPIOA.0          下拉输入
  7.         GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;
  8.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //PA0设置成输入,默认下拉         
  9.         GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0

  10. }
  11. //外部中断0服务程序
  12. void EXTIX_Init(void)
  13. {

  14.            EXTI_InitTypeDef EXTI_InitStructure;
  15.           NVIC_InitTypeDef NVIC_InitStructure;
  16.   KEY_Init();         //        按键端口初始化
  17.    

  18.           RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);        //使能复用功能时钟


  19.    //GPIOA.0          中断线以及中断初始化配置 上升沿触发 PA0  WK_UP
  20.            GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);

  21.           EXTI_InitStructure.EXTI_Line=EXTI_Line0;
  22.         /* EXTI 为中断模式 */
  23.         EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  24.           EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  25.         EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  26.           EXTI_Init(&EXTI_InitStructure);                //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器

  27.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
  28.           NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;                        //使能按键WK_UP所在的外部中断通道
  29.           NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;        //抢占优先级2,
  30.           NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;                                        //子优先级3
  31.           NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                                                //使能外部中断通道
  32.           NVIC_Init(&NVIC_InitStructure);
  33. }

  34. //外部中断0服务程序
  35. void EXTI0_IRQHandler(void)
  36. {
  37.         mcu_reset_wifi();
  38.         mcu_set_wifi_mode(SMART_CONFIG);
  39.         EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位  
  40. }
复制代码

在外部中断函数0里面添加了mcu_reset_wifi(),复位模组,清除全部配网信息,然后调用mcu_set_wifi_mode()函数,参数添加SMART_CONFIG进入smart模式。然后写两个闪灯函数,用于指示配网状态,Led_Blink_Quick()快闪,用于指示进入smart配网模式,Led_Blink_Slow()慢闪,用于指示进入AP配网模式。

  1. void Led_Blink_Quick(void)
  2. {
  3.         LED2_ON;
  4.         Delay(500000);
  5.         LED2_OFF;
  6.         Delay(500000);

  7. }

  8. void Led_Blink_Slow(void)
  9. {
  10.         LED2_ON;
  11.         Delay(5000000);
  12.         LED2_OFF;
  13.         Delay(5000000);

  14. }
复制代码

最后在主函数的while(1)中添加配网状态判断:

现在将MCU与模组通过串口1连接,注意TX与RX反接并共地。按下按键,LED快闪,打开手机APP进行配网,当wifi配置完成灯会熄灭,连接上路由器之后灯会重新点亮,并保持常亮。此过程本人已测试无问题,但是过程比较长不适合贴图,会在视频中展示。

二、添加小夜灯执行功能

配网完成了,那么怎么执行功能呢?在protocol.cdp_download_handle()函数可以处理下发的数据。在此函数中会对下发的指令进行归类,我们找到小夜灯的处理

这里可以进行小夜灯指令的处理,处理完成之后会上报数据,用于更新APP数据。我们跳转进dp_download_light_handle()函数,此函数中有具体的处理,针对不同的开或关会进入不同的if函数。我们在对LED的端口初始化后便可以将开关灯填入。达到不同下发指令实现开关灯。开关功能类似,不赘述。

三、添加手动喂食执行功能

此次涂鸦提供了H桥驱动板,那么我们直接上一个12V的减速电机,每分钟12转,驱动力大,速度慢,易于控制。将电机接到驱动板的U和V接线柱上,控制口PWM1和PWM2接到单片机PA2和PA3。给PA2和PA3不同的高低电平就可以实现正反转,因为电机本身速度比较慢,就不用软件进行控制速度了。而且因为场景的关系,不用控制正反两个反向,只控制正转和停止。

那么老规矩,首先配置GPIO为输出:

  1. void GPIO_CONFIG(void)
  2. {
  3.         GPIO_InitTypeDef GPIO_InitStructure;

  4.         // 打开串口GPIO的时钟
  5.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);        

  6.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
  7.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  8.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  9.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  10. }
复制代码

编写控制函数,参数为投喂量,通过转动时间来控制投喂量,延时时间需要与宠物的饭盒出粮口搭配,不同出粮口修改延时基数。

  1. void motor_concrol_right(uint8_t tim)//电机正转延时后停止
  2. {
  3.         GPIO_SetBits(PWM_PORT,PWM2_GPIO);
  4.         GPIO_ResetBits(PWM_PORT,PWM1_GPIO);
  5.         Delay(10000000*tim);

  6.         GPIO_ResetBits(PWM_PORT,PWM1_GPIO);
  7.         GPIO_ResetBits(PWM_PORT,PWM2_GPIO);

  8.         
  9. }
复制代码

随后在dp_download_handle()函数中的case DPID_MANUAL_FEED:条件下执行该函数,参数由mcu_get_dp_download_value()函数提供,该函数会提取手机下发的出粮量。

36644605c42f90524d.png

因为功能太多,一一介绍很占用篇幅,而且基本是一样的操作。这里跳过,进行下一个环节。

四、触摸屏手动喂食

我在无线的基础上添加屏幕,还是触摸屏,毕竟我们在家的时候还用手机投喂,这不是舍近求远吗?直接手动不是很喵吗?

屏幕太贵?增加成本?占用资源?增加功耗?体积太大?墨水屏就行?

这是我们工程师该考虑的问题吗?帅就完了,成本是资本家考虑的事,反正我又不量产,自己家主子用的,就是要贵,买不起我还做不起吗

那么开始吧,添加屏幕驱动,这里我直接用的野火的电阻触摸屏例程,额,因为屏幕和开发板都是他们家的,开发板太大了,以后考虑做个板子,现在就将就用了,毕竟我还不一定会做成实物,毕竟我外壳还没有。。。。。

那些LCD和触摸板界面初始化就不贴了,主要说我改动的地方。

首先放一张丑图,没有时间美化,仅实现功能。

63709605c4a6804111.png

左边的“加”“减”用于设定手动喂食量,设定好单次喂食量按喂食就会控制电机进行出粮,开灯和关灯就是打开和关闭小夜灯,主界面会实时显示服务器在线状态和单次喂食量,总喂食量以及小夜灯的状态。

代码首先要修改按钮的初始化

  1. /**
  2. * [url=home.php?mod=space&uid=247401]@brief[/url]  Touch_Button_Init 初始化按钮参数
  3. * @param  无
  4. * @retval 无
  5. */
  6. void Touch_Button_Init(void)
  7. {
  8.   /*第一列,主要为颜色按钮*/
  9.   button[0].start_x = BUTTON_START_X;
  10.   button[0].start_y = 0;
  11.   button[0].end_x = BUTTON_START_X+COLOR_BLOCK_WIDTH ;
  12.   button[0].end_y = COLOR_BLOCK_HEIGHT;
  13.   button[0].para = 1;
  14.   button[0].touch_flag = 0;  
  15.   button[0].draw_btn = Draw_Num_Button ;
  16.   button[0].btn_command = Command_Select_Meannum ;
  17.   
  18.   button[1].start_x = BUTTON_START_X;
  19.   button[1].start_y = COLOR_BLOCK_HEIGHT;
  20.   button[1].end_x = BUTTON_START_X+COLOR_BLOCK_WIDTH ;
  21.   button[1].end_y = COLOR_BLOCK_HEIGHT*2;
  22.   button[1].para = 2;
  23.   button[1].touch_flag = 0;  
  24.   button[1].draw_btn = Draw_Num_Button ;
  25.   button[1].btn_command = Command_Select_Light ;
  26.   
  27.   button[2].start_x = BUTTON_START_X;
  28.   button[2].start_y = COLOR_BLOCK_HEIGHT*2;
  29.   button[2].end_x = BUTTON_START_X+COLOR_BLOCK_WIDTH ;
  30.   button[2].end_y = COLOR_BLOCK_HEIGHT*3;
  31.   button[2].para = 3;
  32.   button[2].touch_flag = 0;  
  33.   button[2].draw_btn = Draw_Num_Button ;
  34.   button[2].btn_command = Command_Select_Color ;
  35.   
  36.   button[3].start_x = BUTTON_START_X;
  37.   button[3].start_y = COLOR_BLOCK_HEIGHT*3;
  38.   button[3].end_x = BUTTON_START_X+COLOR_BLOCK_WIDTH ;
  39.   button[3].end_y = COLOR_BLOCK_HEIGHT*4;
  40.   button[3].para = 4;
  41.   button[3].touch_flag = 0;  
  42.   button[3].draw_btn = Draw_Num_Button ;
  43.   button[3].btn_command = Command_Select_Color ;
  44.   
  45.   button[4].start_x = BUTTON_START_X;
  46.   button[4].start_y = COLOR_BLOCK_HEIGHT*4;
  47.   button[4].end_x = BUTTON_START_X+COLOR_BLOCK_WIDTH ;
  48.   button[4].end_y = COLOR_BLOCK_HEIGHT*5;
  49.   button[4].para = 5;
  50.   button[4].touch_flag = 0;  
  51.   button[4].draw_btn = Draw_Num_Button ;
  52.   button[4].btn_command = Command_Select_Color ;
  53.   
  54.   button[5].start_x = BUTTON_START_X;
  55.   button[5].start_y = COLOR_BLOCK_HEIGHT*5;
  56.   button[5].end_x = BUTTON_START_X+COLOR_BLOCK_WIDTH ;
  57.   button[5].end_y = COLOR_BLOCK_HEIGHT*6;
  58.   button[5].para = 6;
  59.   button[5].touch_flag = 0;  
  60.   button[5].draw_btn = Draw_Num_Button ;
  61.   button[5].btn_command = Command_Select_Color ;
  62.   
  63.   button[6].start_x = BUTTON_START_X;
  64.   button[6].start_y = COLOR_BLOCK_HEIGHT*6;
  65.   button[6].end_x = BUTTON_START_X+COLOR_BLOCK_WIDTH ;
  66.   button[6].end_y = COLOR_BLOCK_HEIGHT*7;
  67.   button[6].para = 7;
  68.   button[6].touch_flag = 0;  
  69.   button[6].draw_btn = Draw_Num_Button ;
  70.   button[6].btn_command = Command_Select_Color ;  
  71.   
  72.   button[7].start_x = BUTTON_START_X;
  73.   button[7].start_y = COLOR_BLOCK_HEIGHT*7;
  74.   button[7].end_x = BUTTON_START_X+COLOR_BLOCK_WIDTH ;
  75.   button[7].end_y = LCD_Y_LENGTH;
  76.   button[7].para = CL_BUTTON_GREY;
  77.   button[7].touch_flag = 0;  
  78.   button[7].draw_btn = Draw_Clear_Button ;
  79.   button[7].btn_command = Command_Clear_Palette ;
  80.   
  81.   
  82.   /*第二列,主要为画刷按钮*/
  83.   button[8].start_x = BUTTON_START_X + COLOR_BLOCK_WIDTH;
  84.   button[8].start_y = 0;
  85.   button[8].end_x = BUTTON_START_X + COLOR_BLOCK_WIDTH*2 ;
  86.   button[8].end_y = COLOR_BLOCK_HEIGHT;
  87.   button[8].para = 9;
  88.   button[8].touch_flag = 0;  
  89.   button[8].draw_btn = Draw_Num_Button ;
  90.   button[8].btn_command = Command_Select_Meannum ;
  91.   
  92.   button[9].start_x = BUTTON_START_X + COLOR_BLOCK_WIDTH;
  93.   button[9].start_y = COLOR_BLOCK_HEIGHT;
  94.   button[9].end_x = BUTTON_START_X + COLOR_BLOCK_WIDTH*2 ;
  95.   button[9].end_y = COLOR_BLOCK_HEIGHT*2;
  96.   button[9].para = 10;
  97.   button[9].touch_flag = 0;  
  98.   button[9].draw_btn = Draw_Num_Button ;
  99.   button[9].btn_command = Command_Select_Light ;
  100.   
  101.   button[10].start_x =BUTTON_START_X +  COLOR_BLOCK_WIDTH;
  102.   button[10].start_y = COLOR_BLOCK_HEIGHT*2;
  103.   button[10].end_x = BUTTON_START_X + COLOR_BLOCK_WIDTH*2 ;
  104.   button[10].end_y = COLOR_BLOCK_HEIGHT*3;
  105.   button[10].para = 11;
  106.   button[10].touch_flag = 0;  
  107.   button[10].draw_btn = Draw_Shape_Button ;
  108.   button[10].btn_command = Command_Select_Brush ;
  109.   
  110.   button[11].start_x = BUTTON_START_X + COLOR_BLOCK_WIDTH;
  111.   button[11].start_y = COLOR_BLOCK_HEIGHT*3;
  112.   button[11].end_x = BUTTON_START_X + COLOR_BLOCK_WIDTH*2 ;
  113.   button[11].end_y = COLOR_BLOCK_HEIGHT*4;
  114.   button[11].para = 12;
  115.   button[11].touch_flag = 0;  
  116.   button[11].draw_btn = Draw_Shape_Button ;
  117.   button[11].btn_command = Command_Select_Brush ;
  118.   
  119.   button[12].start_x = BUTTON_START_X + COLOR_BLOCK_WIDTH;
  120.   button[12].start_y = COLOR_BLOCK_HEIGHT*4;
  121.   button[12].end_x = BUTTON_START_X + COLOR_BLOCK_WIDTH*2 ;
  122.   button[12].end_y = COLOR_BLOCK_HEIGHT*5;
  123.   button[12].para = 13;
  124.   button[12].touch_flag = 0;  
  125.   button[12].draw_btn = Draw_Shape_Button ;
  126.   button[12].btn_command = Command_Select_Brush ;
  127.   
  128.   button[13].start_x = BUTTON_START_X + COLOR_BLOCK_WIDTH;
  129.   button[13].start_y = COLOR_BLOCK_HEIGHT*5;
  130.   button[13].end_x = BUTTON_START_X + COLOR_BLOCK_WIDTH*2 ;
  131.   button[13].end_y = COLOR_BLOCK_HEIGHT*6;
  132.   button[13].para = 14;
  133.   button[13].touch_flag = 0;  
  134.   button[13].draw_btn = Draw_Shape_Button ;
  135.   button[13].btn_command = Command_Select_Brush ;
  136.   
  137.   button[14].start_x = BUTTON_START_X + COLOR_BLOCK_WIDTH;
  138.   button[14].start_y = COLOR_BLOCK_HEIGHT*6;
  139.   button[14].end_x = BUTTON_START_X + COLOR_BLOCK_WIDTH*2 ;
  140.   button[14].end_y = COLOR_BLOCK_HEIGHT*7;
  141.   button[14].para = 15;
  142.   button[14].touch_flag = 0;  
  143.   button[14].draw_btn = Draw_Shape_Button ;
  144.   button[14].btn_command = Command_Select_Brush ;   
  145.   
  146.   button[15].start_x = BUTTON_START_X + COLOR_BLOCK_WIDTH;
  147.   button[15].start_y = COLOR_BLOCK_HEIGHT*7;
  148.   button[15].end_x = BUTTON_START_X + COLOR_BLOCK_WIDTH*2 ;
  149.   button[15].end_y = LCD_Y_LENGTH;
  150.   button[15].para = 16;
  151.   button[15].touch_flag = 0;  
  152.   button[15].draw_btn = Draw_Shape_Button ;
  153.   button[15].btn_command = Command_Select_Brush ;
  154. }
复制代码

button[0].para 参数用于定位按键,主函数做如下改变,初始化相关外设。

  1. #include "stm32f10x.h"
  2. #include "./usart/bsp_usart.h"        
  3. #include "./lcd/bsp_ili9341_lcd.h"
  4. #include "./lcd/bsp_xpt2046_lcd.h"
  5. #include "./flash/bsp_spi_flash.h"
  6. #include "./led/bsp_led.h"
  7. #include "palette.h"
  8. #include <string.h>
  9. #include "mcu_api.h"
  10. #include "protocol.h"
  11. #include "system.h"
  12. #include "wifi.h"
  13. #include "concrol.h"


  14. extern int MANUAL_FEED_NUM;
  15. char dispBuff[100];
  16. extern int MANUAL_FEED_SUM;
  17. int main(void)
  18. {               
  19.         //LCD 初始化
  20.         ILI9341_Init();  
  21.         
  22.         //触摸屏初始化
  23.         XPT2046_Init();
  24.         //从FLASH里获取校正参数,若FLASH无参数,则使用模式3进行校正
  25.         Calibrate_or_Get_TouchParaWithFlash(3,0);

  26.         /* USART config */
  27.         USART_Config();  
  28.         LED_GPIO_Config();
  29.         EXTIX_Init();

  30.         //其中0、3、5、6 模式适合从左至右显示文字,
  31.         //不推荐使用其它模式显示文字        其它模式显示文字会有镜像效果                        
  32.         //其中 6 模式为大部分液晶例程的默认显示方向  
  33.   ILI9341_GramScan ( 3 );        
  34.         
  35.         //绘制触摸画板界面
  36.         Palette_Init(LCD_SCAN_MODE);
  37.         wifi_protocol_init();
  38.         GPIO_CONFIG();               
  39.         LCD_SetFont(&Font8x16);        
  40.         LCD_SetColors(RED,BLACK);
  41.         sprintf(dispBuff,"手动投喂量: %d ",MANUAL_FEED_NUM);
  42.         ILI9341_DispString_EN_CH(2*48,2*48,dispBuff);
  43.         ILI9341_DisplayStringEx(2*48,0*48,16,16,(uint8_t *)"服务器在线!!!",0);        
  44.         while ( 1 )
  45.         {               
  46.                         wifi_uart_service();//心跳检测
  47.                         //触摸检测函数,本函数至少10ms调用一次
  48.                         XPT2046_TouchEvenHandler();
  49.                         LCD_SetFont(&Font8x16);        
  50.                         LCD_SetColors(RED,BLACK);
  51.                         sprintf(dispBuff,"总喂食量: %d ",MANUAL_FEED_SUM);
  52.                         ILI9341_DispString_EN_CH(2*48,1*48,dispBuff);      
  53.                         switch(mcu_get_wifi_work_state())
  54.                         {

  55.                                 case SMART_CONFIG_STATE:
  56.                                         //处于 Smart 配置状态,即 LED 快闪
  57.                                         Led_Blink_Quick();
  58.                                 break;
  59.                                 case AP_STATE:
  60.                                         //处于 AP 配置状态,即 LED 慢闪
  61.                                         Led_Blink_Slow();
  62.                                 break;
  63.                                 case WIFI_NOT_CONNECTED:
  64.                                         //Wi-Fi 配置完成,正在连接路由器,即 LED 常暗
  65.                                         LED2_OFF;
  66.                                 break;
  67.                                 case WIFI_CONNECTED:
  68.                                         //路由器连接成功,即 LED 常亮
  69.                                         LED2_ON;
  70.                                         LCD_SetFont(&Font8x16);        
  71.                                         LCD_SetColors(RED,BLACK);
  72.                                         ILI9341_DisplayStringEx(2*48,0*48,16,16,(uint8_t *)"服务器在线!!!",0);
  73.                                 break;
  74.                                 default:break;
  75.                         }
  76.         

  77.                         
  78.         }
  79.                
  80. }
复制代码

主函数就是初始化相关外设,显示开机需要打印的文字,在while(1)中添加XPT2046_TouchEvenHandler();用于触摸检测,并循环检测总喂食量用于实时显示,如果路由器连接成功会打印“服务器在线”的提示语。

XPT2046_TouchEvenHandler()函数原型:

  1. /**
  2.         * [url=home.php?mod=space&uid=247401]@brief[/url]   检测到触摸中断时调用的处理函数,通过它调用tp_down 和tp_up汇报触摸点
  3.         *        [url=home.php?mod=space&uid=536309]@NOTE[/url]          本函数需要在while循环里被调用,也可使用定时器定时调用
  4.         *                        例如,可以每隔5ms调用一次,消抖阈值宏DURIATION_TIME可设置为2,这样每秒最多可以检测100个点。
  5.         *                                                可在XPT2046_TouchDown及XPT2046_TouchUp函数中编写自己的触摸应用
  6.         * @param   none
  7.         * @retval  none
  8.         */
  9. void XPT2046_TouchEvenHandler(void )
  10. {
  11.           static strType_XPT2046_Coordinate cinfo={-1,-1,-1,-1};
  12.         
  13.                 if(XPT2046_TouchDetect() == TOUCH_PRESSED)
  14.                 {
  15.                         //获取触摸坐标
  16.                         XPT2046_Get_TouchedPoint(&cinfo,strXPT2046_TouchPara);
  17.                         
  18.                         //输出调试信息到串口
  19.                         XPT2046_DEBUG("x=%d,y=%d",cinfo.x,cinfo.y);
  20.                         
  21.                         //调用触摸被按下时的处理函数,可在该函数编写自己的触摸按下处理过程
  22.                         XPT2046_TouchDown(&cinfo);
  23.                         
  24.                         /*更新触摸信息到pre xy*/
  25.                         cinfo.pre_x = cinfo.x; cinfo.pre_y = cinfo.y;  
  26.                 }
  27.                 else
  28.                 {                        
  29.                         //调用触摸被释放时的处理函数,可在该函数编写自己的触摸释放处理过程
  30.                         XPT2046_TouchUp(&cinfo);
  31.                         
  32.                         /*触笔释放,把 xy 重置为负*/
  33.                         cinfo.x = -1;
  34.                         cinfo.y = -1;
  35.                         cinfo.pre_x = -1;
  36.                         cinfo.pre_y = -1;
  37.                 }
  38. }
复制代码

按键按下会触发XPT2046_TouchDown()函数,该函数原型为:

  1. /**
  2.   * @brief   触摸屏被按下的时候会调用本函数
  3.   * @param  touch包含触摸坐标的结构体
  4.   * [url=home.php?mod=space&uid=536309]@NOTE[/url]  请在本函数中编写自己的触摸按下处理应用
  5.   * @retval 无
  6.   */
  7. void XPT2046_TouchDown(strType_XPT2046_Coordinate * touch)
  8. {
  9.         //若为负值表示之前已处理过
  10.         if(touch->pre_x == -1 && touch->pre_x == -1)
  11.                 return;
  12.         
  13.         /***在此处编写自己的触摸按下处理应用***/
  14.   
  15.         /*处理触摸画板的选择按钮*/
  16.   Touch_Button_Down(touch->x,touch->y);
  17.   
  18.   /*处理描绘轨迹*/
  19.   Draw_Trail(touch->pre_x,touch->pre_y,touch->x,touch->y,&brush);
  20.         
  21.         /***在上面编写自己的触摸按下处理应用***/        
  22. }
复制代码

此函数触发Touch_Button_Down();

  1. void Touch_Button_Down(uint16_t x,uint16_t y)
  2. {
  3.   uint8_t i;
  4.   for(i=0;i<BUTTON_NUM;i++)
  5.   {
  6.     /* 触摸到了按钮 */
  7.     if(x<=button[i].end_x && y<=button[i].end_y && y>=button[i].start_y && x>=button[i].start_x )
  8.     {
  9.       if(button[i].touch_flag == 0)     /*原本的状态为没有按下,则更新状态*/
  10.       {
  11.       button[i].touch_flag = 1;         /* 记录按下标志 */
  12.       
  13.       button[i].draw_btn(&button[i]);  /*重绘按钮*/
  14.       }        
  15.       
  16.     }
  17.     else if(button[i].touch_flag == 1) /* 触摸移出了按键的范围且之前有按下按钮 */
  18.     {
  19.       button[i].touch_flag = 0;         /* 清除按下标志,判断为误操作*/
  20.       
  21.       button[i].draw_btn(&button[i]);   /*重绘按钮*/
  22.     }

  23.   }

  24. }
复制代码

此函数会改变相应按键的按下标志位,触发按键按下的函数处理。之后会重绘按键,函数为Draw_Num_Button(),这里不贴了,量太大。这里举例说明,比如按下了开灯键,会触发Command_Select_Light()

77399605c546e6042d.png

  1. /**
  2. * @brief  Command_Select_Light 夜灯控制
  3. * @param  btn Touch_Button 类型的按键参数
  4. * @retval 无
  5. */
  6. static void Command_Select_Light(void *btn)
  7. {
  8.          Touch_Button *ptr = (Touch_Button *)btn;
  9.         if(ptr->para==2)
  10.         {
  11.                 /* 开启led灯        */
  12.                 LED1_ON;
  13.                 LCD_SetFont(&Font8x16);        
  14.                 LCD_SetColors(RED,BLACK);
  15.                 ILI9341_DispString_EN_CH(2*48,3*48,"Light  On");
  16.         }
  17.         if(ptr->para==10)
  18.         {
  19.                 /* 关闭led灯        */
  20.                 LED1_OFF;
  21.                 LCD_SetFont(&Font8x16);        
  22.                 LCD_SetColors(RED,BLACK);
  23.                 ILI9341_DispString_EN_CH(2*48,3*48,"Light Off");               
  24.         }
  25. }
复制代码

此处代码量大且杂,这里就不一一介绍,若想看具体的代码可git或直接下载。

在写这篇文章的时候H桥驱动烧了,视频又要延迟更新了,真的抱歉。先上代码吧。

1617261567859.gif





  

涂鸦IOT.rar

6.1 MB, 下载次数: 2

使用特权

评论回复
 楼主 | 2021-3-26 15:25 | 显示全部楼层
本帖最后由 呐咯密密 于 2021-4-1 15:36 编辑

咱们书接上回,昨天发帖的时候把H桥驱动板烧了,于是昨晚回家就翻找自己的垃圾箱,想找一个旧的驱动板,发现了以前买的继电器模块,这不一样吗。同时还有当时毕业设计剩下的DHT11温湿度模块,正好,物联网设计嘛,加一个这玩意也不算跑题呀。
22613605d8b46d7db6.png
于是乎,咱们的页面也及时更新。
77295605d8ba033094.png
代码也要添加DHT11的驱动:
DTH11.C
  1. #include "dht11.h"
  2. #include "delay.h"

  3. //复位DHT11
  4. void DHT11_Rst(void)           
  5. {                 
  6.         DHT11_IO_OUT();         //SET OUTPUT
  7.     DHT11_DQ_OUT=0;         //拉低DQ
  8.     delay_ms(20);            //拉低至少18ms
  9.     DHT11_DQ_OUT=1;         //DQ=1
  10.         delay_us(30);             //主机拉高20~40us
  11. }
  12. //等待DHT11的回应
  13. //返回1:未检测到DHT11的存在
  14. //返回0:存在
  15. u8 DHT11_Check(void)            
  16. {   
  17.         u8 retry=0;
  18.         DHT11_IO_IN();//SET INPUT         
  19.     while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us
  20.         {
  21.                 retry++;
  22.                 delay_us(1);
  23.         };         
  24.         if(retry>=100)return 1;
  25.         else retry=0;
  26.     while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us
  27.         {
  28.                 retry++;
  29.                 delay_us(1);
  30.         };
  31.         if(retry>=100)return 1;            
  32.         return 0;
  33. }
  34. //从DHT11读取一个位
  35. //返回值:1/0
  36. u8 DHT11_Read_Bit(void)                          
  37. {
  38.          u8 retry=0;
  39.         while(DHT11_DQ_IN&&retry<100)//等待变为低电平
  40.         {
  41.                 retry++;
  42.                 delay_us(1);
  43.         }
  44.         retry=0;
  45.         while(!DHT11_DQ_IN&&retry<100)//等待变高电平
  46.         {
  47.                 retry++;
  48.                 delay_us(1);
  49.         }
  50.         delay_us(40);//等待40us
  51.         if(DHT11_DQ_IN)return 1;
  52.         else return 0;                  
  53. }
  54. //从DHT11读取一个字节
  55. //返回值:读到的数据
  56. u8 DHT11_Read_Byte(void)   
  57. {        
  58.     u8 i,dat;
  59.     dat=0;
  60.         for (i=0;i<8;i++)
  61.         {
  62.                    dat<<=1;
  63.             dat|=DHT11_Read_Bit();
  64.     }                                                   
  65.     return dat;
  66. }
  67. //从DHT11读取一次数据
  68. //temp:温度值(范围:0~50°)
  69. //humi:湿度值(范围:20%~90%)
  70. //返回值:0,正常;1,读取失败
  71. u8 DHT11_Read_Data(u8 *temp,u8 *humi)   
  72. {        
  73.          u8 buf[5];
  74.         u8 i;
  75.         DHT11_Rst();
  76.         if(DHT11_Check()==0)
  77.         {
  78.                 for(i=0;i<5;i++)//读取40位数据
  79.                 {
  80.                         buf[i]=DHT11_Read_Byte();
  81.                 }
  82.                 if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
  83.                 {
  84.                         *humi=buf[0];
  85.                         *temp=buf[2];
  86.                 }
  87.         }else return 1;
  88.         return 0;            
  89. }
  90. //初始化DHT11的IO口 DQ 同时检测DHT11的存在
  91. //返回1:不存在
  92. //返回0:存在            
  93. u8 DHT11_Init(void)
  94. {         
  95.          GPIO_InitTypeDef  GPIO_InitStructure;
  96.          
  97.          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);         //使能PG端口时钟
  98.         
  99.          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;                                 //PG11端口配置
  100.          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //推挽输出
  101.          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  102.          GPIO_Init(GPIOC, &GPIO_InitStructure);                                 //初始化IO口
  103.          GPIO_SetBits(GPIOC,GPIO_Pin_11);                                                 //PG11 输出高
  104.                            
  105.         DHT11_Rst();  //复位DHT11
  106.         return DHT11_Check();//等待DHT11的回应
  107. }







复制代码
DTH11.H
  1. #ifndef __DHT11_H
  2. #define __DHT11_H
  3. #include "sys.h"  

  4. //IO方向设置
  5. #define DHT11_IO_IN()  {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=8<<12;}
  6. #define DHT11_IO_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3<<12;}
  7. ////IO操作函数                                                                                          
  8. #define        DHT11_DQ_OUT PCout(11) //数据端口        PA0
  9. #define        DHT11_DQ_IN  PCin(11)  //数据端口        PA0


  10. u8 DHT11_Init(void);//初始化DHT11
  11. u8 DHT11_Read_Data(u8 *temp,u8 *humi);//读取温湿度
  12. u8 DHT11_Read_Byte(void);//读出一个字节
  13. u8 DHT11_Read_Bit(void);//读出一个位
  14. u8 DHT11_Check(void);//检测是否存在DHT11
  15. void DHT11_Rst(void);//复位DHT11   
  16. #endif
复制代码
然后再while(1)中循环采集数据,并显示在屏幕上:
  1. DHT11_Read_Data(&temperature,&humidity);        //读取温湿度值
  2.                         sprintf(humbuf,"湿度: %d ",humidity);
  3.                         ILI9341_DispString_EN_CH(4*48,4*48,humbuf);

  4.                         sprintf(tempbuff,"温度: %d ",temperature);
  5.                         ILI9341_DispString_EN_CH(2*48,4*48,tempbuff);  
复制代码
1617262435890.gif

使用特权

评论回复
| 2021-3-26 20:25 | 显示全部楼层
若能不断简化那就更好了

使用特权

评论回复
| 2021-3-28 15:39 | 显示全部楼层
没必要搞得这么繁杂吧?

使用特权

评论回复
 楼主 | 2021-3-28 19:32 | 显示全部楼层
ezcui 发表于 2021-3-28 15:39
没必要搞得这么繁杂吧?

按照产品的思路,确实复杂了,但是我这不是从产品角度考虑的,只是想发挥一下。而且我连外壳都没做呢

使用特权

评论回复
 楼主 | 2021-4-1 15:23 | 显示全部楼层
已追加WS2812的驱动,增加华丽程度:硬件太丑,B格不够,只好彩灯来凑--STM32F103 SPI驱动WS2812

使用特权

评论回复
| 2021-4-1 22:35 | 显示全部楼层
非常不错 涂鸦的模块固件要钱的吧?

使用特权

评论回复
 楼主 | 2021-4-2 09:08 | 显示全部楼层
qjp1988113 发表于 2021-4-1 22:35
非常不错 涂鸦的模块固件要钱的吧?

固件不要钱呀

使用特权

评论回复
| 2021-4-2 14:40 | 显示全部楼层
感谢分享资料,有养宠物,学习下~

使用特权

评论回复
扫描二维码,随时随地手机跟帖
返回列表 发新帖 本帖赏金 101.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

我要发帖 我要提问 投诉建议 申请版主

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式

论坛热帖

在线客服 快速回复 返回顶部 返回列表