[RISC-V MCU 应用开发] 基于CH32V307的物联网远程控制

[复制链接]
 楼主| 51xlf 发表于 2022-7-18 22:57 | 显示全部楼层 |阅读模式
<
#申请原创#  @21小跑堂

最近在研究CH32V307的板子,这个板子性能还是非常强大的。CH32V307是基于32位RISC-V设计的互联型微控制器,配备了硬件堆栈区、快速中断入口,在标准RISC-V基础上大大提高了中断响应速度。加入单精度浮点指令集,扩充堆栈区,具有更高的运算性能。
看看CH32V307在物联网控制方面的应用如何,这就就做了一些相关的测试。使用CH32V307和ESP8266实现阿里云物联网平台的连接,并能远程控制CH32V307开发板上的LED灯的通断。
首先要建立的是下位机的设计,这里就不再赘述如何串口烧录ESP8266的AT固件了,网上有很多可以参考的设计。
现在有MQTT固件,使用也简答。我没有使用这类固件,使用的是正常的AT固件。通过TCP建立连接,然后与MQTT broker联系的。
CH32V307与ESP8266使用的是串口2的通信,这里需要配置波特率为115200,并开启相关的中断。
  1. void USART2_CFG(void)
  2. {
  3.     GPIO_InitTypeDef  GPIO_InitStructure = {0};
  4.     USART_InitTypeDef USART_InitStructure = {0};
  5.     NVIC_InitTypeDef  NVIC_InitStructure = {0};

  6.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2 , ENABLE);
  7.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);

  8.     /* USART2 TX-->A.2   RX-->A.3 */
  9.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  10.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  11.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  12.     GPIO_Init(GPIOA, &GPIO_InitStructure);
  13.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  14.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  15.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  16.     USART_InitStructure.USART_BaudRate = 115200;
  17.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  18.     USART_InitStructure.USART_StopBits = USART_StopBits_1;
  19.     USART_InitStructure.USART_Parity = USART_Parity_No;
  20.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  21.     USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;

  22.     USART_Init(USART2, &USART_InitStructure);
  23.     USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);


  24.     NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
  25.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  26.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  27.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  28.     NVIC_Init(&NVIC_InitStructure);


  29.     USART_Cmd(USART2, ENABLE);
  30. }
并将指令发送到ESP8266和接收ESP266的数据
  1. void USART2_IRQHandler(void)
  2. {
  3.     u8 uartR=0;
  4.     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
  5.     {
  6.         uartR= USART_ReceiveData(USART2);
  7.         if(USART1_RX_STA<USART1_MAX)  //还可以接收数据
  8.        {
  9.            usart1_rxbuf[USART1_RX_STA++]=uartR;   //记录接收到的值
  10.        } else
  11.        {
  12.            USART1_RX_STA=0;                //计数归零
  13.        }

  14.     }
  15. }
初始化ESP8266的时候需要,配置ESP8266位STA模式并与路由器建立连接。
  1. uint8_t ESP8266_Init(void)
  2. {
  3.     //清空发送和接收数组
  4.     memset(usart1_txbuf,0,sizeof(usart1_txbuf));
  5.     memset(usart1_rxbuf,0,sizeof(usart1_rxbuf));

  6.     ESP8266_ExitUnvarnishedTrans();                //退出透传
  7.     Delay_Ms(500);
  8.     ESP8266_ATSendString("AT+RST\r\n");
  9.     Delay_Ms(2000);
  10.     if(ESP8266_Check()==0)              //使用AT指令检查ESP8266是否存在
  11.     {
  12.         return 0;
  13.     }
  14.     memset(usart1_rxbuf,0,sizeof(usart1_rxbuf));    //清空接收缓冲
  15.     ESP8266_ATSendString("ATE1\r\n");             //关闭回显
  16.     if(FindStr((char*)usart1_rxbuf,"OK",500)==0)  //设置不成功
  17.     {
  18.         return 0;
  19.     }
  20.     return 1;                         //设置成功
  21. }
这里用到是strstr的指令,判断是否有我们要求的返回值。FindStr这里的代码是这样规划的。
通过多次演示,判断是否收到数据,如果没有收到数据或者不一样的数据,则判断不正确。
  1. uint8_t FindStr(char* dest,char* src,uint16_t retry_nms)
  2. {
  3.     int retry_nms_t = retry_nms;                   //超时时间
  4.     while(strstr((char*)usart1_rxbuf,src)== NULL && retry_nms_t)//等待串口接收完毕或超时退出
  5.     {
  6.         Delay_Ms(10);retry_nms_t--;
  7.     }
  8.     printf(usart1_rxbuf);
  9.     if(retry_nms_t>=0) return 1;

  10.     return 0;
  11. }
然后就是需要去连接WIFI模块了。需要提前写入路由器的名称和代码
  1. uint8_t ESP8266_ConnectAP(char* ssid,char* pswd)
  2. {
  3.     uint8_t cnt=5;
  4.     while(cnt--)
  5.     {
  6.         memset(usart1_rxbuf,0,sizeof(usart1_rxbuf));
  7.         ESP8266_ATSendString("AT+CWMODE_CUR=1\r\n");              //设置为STATION模式
  8.         if(FindStr((char*)usart1_rxbuf,"OK",200) != 0)
  9.         {
  10.             break;
  11.         }
  12.     }
  13.     if(cnt == 0)
  14.         return 0;
  15.     cnt=2;
  16.     while(cnt--)
  17.     {
  18.         memset(usart1_txbuf,0,sizeof(usart1_txbuf));//清空发送缓冲
  19.         memset(usart1_rxbuf,0,sizeof(usart1_rxbuf));//清空接收缓冲
  20.         sprintf((char*)usart1_txbuf,"AT+CWJAP_CUR="%s","%s"\r\n",ssid,pswd);//连接目标AP
  21.         ESP8266_ATSendString((char*)usart1_txbuf);
  22.         if(FindStr((char*)usart1_rxbuf,"GOT IP",8000)!=0)                      //连接成功且分配到IP
  23.         {
  24.             return 1;
  25.         }
  26.     }
  27.     return 0;
  28. }
在编写代码之前,我们要先搭建好阿里云物联网平台,建立产品和设备。
要建立设备,设备名称随便起。
1.jpg

建立产品以后,需要建立的是物模型。因为我们只是做一个简单的LED的控制和状态显示,所以只添加了一个LED即可。
2.jpg
在产品里面就是需要建立设备了,这里设备名称随便起,但是必须是英文,后面需要用到的。
3.jpg
点击查看设备的三元素,填写到程序中,生产用户名 ID和密码。
4.jpg

我们接着回复编写我们的程序,连接阿里云。
这里需要的是阿里云的IP地址,https://help.aliyun.com/product/30520.html 具体的应用框架,可以看到这里。

  1. if(ESP8266_ConnectServer("TCP",ServerIP,1883)!=0)
  2.     {
  3.         printf("Conn to MQTT Server !\r\n");
  4.     }
  5.     else printf("Connto MQTT Fail!\r\n");
这里是生成三要素的代码。
  1. void AliIoT_Parameter_Init(void)
  2. {        
  3.         char temp[128];                                                       //计算加密的时候,临时使用的缓冲区

  4.         memset(ClientID,128,0);                                               //客户端ID的缓冲区全部清零
  5.         sprintf(ClientID,"%s|securemode=3,signmethod=hmacsha1|",DEVICENAME);  //构建客户端ID,并存入缓冲区
  6.         ClientID_len = strlen(ClientID);                                      //计算客户端ID的长度
  7.         
  8.         memset(Username,128,0);                                               //用户名的缓冲区全部清零
  9.         sprintf(Username,"%s&%s",DEVICENAME,PRODUCTKEY);                      //构建用户名,并存入缓冲区
  10.         Username_len = strlen(Username);                                      //计算用户名的长度
  11.         
  12.         memset(temp,128,0);                                                                      //临时缓冲区全部清零
  13.         sprintf(temp,"clientId%sdeviceName%sproductKey%s",DEVICENAME,DEVICENAME,PRODUCTKEY);     //构建加密时的明文   
  14.         utils_hmac_sha1(temp,strlen(temp),Passward,DEVICESECRE,DEVICESECRE_LEN);                 //以DeviceSecret为秘钥对temp中的明文,进行hmacsha1加密,结果就是密码,并保存到缓冲区中
  15.         Passward_len = strlen(Passward);                                                         //计算用户名的长度
  16.         
  17.         memset(ServerIP,128,0);  
  18.         sprintf(ServerIP,"%s.iot-as-mqtt.cn-shanghai.aliyuncs.com",PRODUCTKEY);                    //构建服务器域名
  19.         //sprintf(ServerIP,"106.54.182.59");                    //构建服务器域名
  20.         ServerPort = 1883;   
至于如何使用MQTT连接 Broker,这里也不赘述了,有代码,直接应用即可。
  1. MQTT_Connect(ClientID, Username, Passward)
连接以后,可以看到,设备已经显示上线了。
5.jpg

我们在串口上也可以看到输出的日志。
6.jpg

这里是定时上传LED状态到阿里云物联网平台的。固定的json格式,不能修改,根据前面定义的物模型编写的。
  1.             if(Connnect_flag==1) {//有客户端连接,发送到客户端
  2.                 sprintf(s_temp,"{"id":1,"params":{"led":%d},"version":"1.0","method":"thing.event.property.post"}",
  3.                        led_state);
  4.                 MQTT_PublishData(P_TOPIC_NAME,s_temp,0);
  5.             }
这里显示的就是LED的状态。当前设备为关闭状态。
8.jpg
我们可以使用设备模式实现控制指令的下发。
QQ截图20220718225113.jpg
当我们选择LED为关闭或者开启状态的时候,在单片机上就会收到这样的数据。
9.jpg
里面json数据"\"led\":1"或者"\"led\":0"便是对LED的状态控制。
我们在程序连判断一下,接收到数据是哪个,就可以对相应的LED进行控制了
  1. if(strstr(usart1_rxbuf+4,""led":1"))led_state=1;
  2.             else if(strstr(usart1_rxbuf+4,""led":0"))led_state=0;
  3.             if(led_state==0)GPIO_SetBits(GPIOE,GPIO_Pin_5);
  4.             else GPIO_ResetBits(GPIOE,GPIO_Pin_5);
来看看开发板的验证吧。绿色框就是LED状态的变化。附上源代码
游客,如果您要查看本帖隐藏内容请回复


12.jpg 11.jpg

打赏榜单

21小跑堂 打赏了 50.00 元 2022-07-20
理由:恭喜通过原创文章审核!请多多加油哦!

评论

厉害  发表于 2024-10-31 13:56
您好,能给一下源代码吗?  发表于 2023-7-7 19:13
xdqfc 发表于 2022-7-20 09:29 | 显示全部楼层
不太建议用这些云平台的东西,网络通信最好还是使用自己的服务器,数据交换自己编程,来龙去脉自己心里清清楚楚,最关键的是速度不是这些云平台能比的。

评论

[url=home.php?mod=space&uid=2540432]@呐咯密密[/url] :对,大部分用户只是测试。用emqx 跑mqtt比这个还简单。  发表于 2022-7-20 11:51
不是谁都有能力搭建自己的服务器。  发表于 2022-7-20 10:19
 楼主| 51xlf 发表于 2022-7-20 11:50 | 显示全部楼层
xdqfc 发表于 2022-7-20 09:29
不太建议用这些云平台的东西,网络通信最好还是使用自己的服务器,数据交换自己编程,来龙去脉自己心里清清 ...

用EMQX自己搭建不比这个简单?
xdqfc 发表于 2022-7-20 16:52 | 显示全部楼层
51xlf 发表于 2022-7-20 11:50
用EMQX自己搭建不比这个简单?

之前也玩过这些云平台的东西,好不容易做了个产品,刚想再升级一下自己的产品,没有想到的是平台公司不玩了,不知道是不是倒闭了,害得自己白忙活一场。拥有自己的服务器才是最可靠的。
 楼主| 51xlf 发表于 2022-7-20 20:20 | 显示全部楼层
xdqfc 发表于 2022-7-20 16:52
之前也玩过这些云平台的东西,好不容易做了个产品,刚想再升级一下自己的产品,没有想到的是平台公司不玩 ...

本来就是薅羊毛的事,
xdqfc 发表于 2022-7-21 11:09 | 显示全部楼层
51xlf 发表于 2022-7-20 20:20
本来就是薅羊毛的事,

呵呵,所以,后来我用的是自己的服务器,数据交换程序是自己开发的,用的放心,价格不贵。

评论

[url=home.php?mod=space&uid=315743]@xdqfc[/url] :就是单纯的自己想倒腾一下,其实别的都不重要,但是数据没办法保存下来就很难受  发表于 2022-7-26 16:28
[url=home.php?mod=space&uid=2823628]@F99343441[/url] :呵呵,是自己做平台服务器啊,需要卖给客户用吧,我是自己产品上用,也不需要什么注册乱七八糟的东西。  发表于 2022-7-24 10:42
我也是自己搭了个云服务器,然而只能实现个数据转发。用户注册啊,数据保存,云端报警一直没做出来,太难了  发表于 2022-7-21 17:19
enqying 发表于 2022-7-24 11:43 | 显示全部楼层
做的不错 很好
kjkujkj22 发表于 2022-8-4 15:27 | 显示全部楼层
做的不错的,很棒的,感谢楼主分享。
麻花油条 发表于 2022-8-5 16:38 来自手机 | 显示全部楼层
做的很棒,很不错,优秀的人
tail066 发表于 2022-8-7 14:39 | 显示全部楼层
很不错,物联网会是大趋势
cyj1232 发表于 2022-8-13 17:22 | 显示全部楼层
学习学习
sheflynn 发表于 2022-8-16 20:02 | 显示全部楼层
wifi通信吗  
mituzu 发表于 2022-8-16 21:18 | 显示全部楼层
这个的应用不错。  
robertesth 发表于 2022-8-18 17:30 | 显示全部楼层
这个效果可以。      
ulystronglll 发表于 2022-8-18 19:33 | 显示全部楼层
这个自带通信模块吗  
xiaoyaodz 发表于 2022-8-19 20:10 | 显示全部楼层
相应的速度怎么样?     
hilahope 发表于 2022-8-20 15:49 | 显示全部楼层
CH32V307的性能怎么样   
mmbs 发表于 2022-8-20 20:02 | 显示全部楼层
可以连接其他的云吗   
claretttt 发表于 2022-10-5 16:55 | 显示全部楼层
怎样实现远程控制电脑开机               
burgessmaggie 发表于 2022-10-5 17:20 | 显示全部楼层
stm32和ch32用起来有差别吗
您需要登录后才可以回帖 登录 | 注册

本版积分规则

547

主题

9919

帖子

24

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

547

主题

9919

帖子

24

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