STM32-笔记34-4G遥控灯

4G接线

一、项目需求

服务器通过4G模块远程遥控开关灯。

二、项目实现

复制项目文件夹38-wifi控制风扇项目

重命名为39-4G遥控点灯

打开项目文件

加载文件

main.c

cpp 复制代码
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "e840.h"
#include "string.h"

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();//初始化led灯
    uart1_init(115200);//这里是跟电脑相连接的串口波特率
    e840_init(9600);//我这里的e840的波特率为9600
   // printf("hello word!\r\n");
    
    char recv_data[E840_RX_BUF_SIZE];
    while(1)
    { 
        e840_receive_data(recv_data);//现在是把接收到的数据传到recv_data这里了
        if(strstr(recv_data,"ON") != NULL)//判断我们接收到的字符串里面是否有ON这个值,有的话打卡风扇
            led1_ON();
        else if(strstr(recv_data,"OFF") != NULL)//没有不打开
            led1_OFF();
        delay_ms(10);
//        esp8266_test();
//        delay_ms(500);
    }
}

e840.c

cpp 复制代码
#include "sys.h"
#include "e840.h"
#include "string.h"
#include "stdio.h"
#include "delay.h"
#include "stdarg.h"

uint8_t e840_rx_buf[E840_RX_BUF_SIZE];//定义一个数组,用来保存接收的缓冲区
uint8_t e840_tx_buf[E840_TX_BUF_SIZE];//定义一个数组,用来保存发送的缓冲区
uint16_t e840_cnt = 0,e840_cntPre = 0; //定义一个计数器,和保存计数器原本状态的变量


UART_HandleTypeDef e840_handle = {0};

void e840_uart_init(uint32_t baudrate)
{
    e840_handle.Instance = USART2;
    e840_handle.Init.BaudRate = baudrate;  //波特率
    e840_handle.Init.Mode = UART_MODE_TX_RX;//收发模式;
    e840_handle.Init.Parity = UART_PARITY_NONE;//无校验位
    e840_handle.Init.WordLength = UART_WORDLENGTH_8B;  //字长:8个字长
    e840_handle.Init.StopBits = UART_STOPBITS_1; //停止位:1个停止位
    e840_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; //无硬件流控
    
    HAL_UART_Init(&e840_handle);
}

void USART2_IRQHandler(void)
{
    uint8_t receive_data = 0;
    //这个函数是用来检查特定的UART接口(在这个例子中是e840_handle所代表的UART接口)是否有数据可读
    if(__HAL_UART_GET_FLAG(&e840_handle,UART_FLAG_RXNE) != RESET)//关注RXNE这个标志位的值是不是不为reset(0)
    {
        if(e840_cnt >= sizeof(e840_rx_buf))//如果接收的字符长度大于字符缓冲区的长度,则把缓冲区长度置0
            e840_cnt = 0;
        //如果RXNE的值为1,证明有数据,所以需要接收数据
        HAL_UART_Receive(&e840_handle,&receive_data,1,1000);//句柄,接收的数据存放在哪?接收数据的个数,超时时间
        e840_rx_buf[e840_cnt++] = receive_data;//将接收的数据存放在e840rx_buf数组中
        
        //HAL_UART_Transmit(&e840_handle,&receive_data,1,1000);//发送数据:句柄,要发送的数据,发送数据的长度,超时
    }
}
//这个函数主要用来判断e840cnt有没有动,如果没有动证明接收完成了
uint8_t e840_wait_receive(void)
{
    if(e840_cnt == 0)//如果cnt为0证明,出现了错误
        return E840_ERROR;//出现错误
    if(e840_cnt == e840_cntPre)//判断当前cnt和上一个cnt是否一致,如果是一致的证明数据不动了,传输完成
    {
        e840_cnt = 0;//cnt清0
        return E840_EOK;//数据接收完成
    }
    e840_cntPre = e840_cnt;//把当前计数器cnt的值赋给之前计数器
    return E840_ERROR;//
     
}
//把接收寄存器的内容清空
void e840_rx_clear(void)
{
    //把接收缓冲器清空
    memset(e840_rx_buf,0,sizeof(e840_rx_buf));
    //清空长度
    e840_cnt = 0;
}
//这个函数在while循环里,来一直判断当前数据是否接收完
uint16_t e840_receive_data(char *recv_data)
{
    if(e840_wait_receive() == E840_EOK)//判断数据是否接受完整
    {
        printf("e840 recv: %s\r\n",e840_rx_buf);//接收完整,打印数据
        //我们把e840_rx_buf中的内容通过memcpy的方式,全部copy到recv_data中
        memcpy(recv_data,e840_rx_buf,strlen((const char *)e840_rx_buf));
        e840_rx_clear();//清除当前接收
        //返回e840_rx_buf的内容以及长度
        return strlen((const char*)recv_data);
    }
    return 0;
}
//发送数据的函数
void e840_send_data(char *fmt,...)
{
    va_list ap;
    uint16_t len;
    va_start(ap,fmt);
    vsprintf((char *)e840_tx_buf,fmt,ap);
    va_end(ap);
    
    len = strlen((const char *)e840_tx_buf);
    HAL_UART_Transmit(&e840_handle,e840_tx_buf,len,100);
}

void e840_init(uint32_t baudrate)
{
    //printf("e840初始化开始...\r\n");
    //e840串口初始化
    e840_uart_init(baudrate);
   
}

e840.h

cpp 复制代码
#ifndef __E840_H__
#define __E840_H__

#include "sys.h"

#define E840_RX_BUF_SIZE         128 //接收的长度
#define E840_TX_BUF_SIZE         64  //发送的长度

#define E840_EOK                  0  //宏定义错误代码 ok
#define E840_ERROR                1  //错误
#define E840_ETIMEOUT             2  //超时
#define E840_EINVAL               3  //数据非法

void e840_init(uint32_t baudrate);
uint16_t e840_receive_data(char *recv_data);
//void e840_test(void);

#endif

注意:

执行结果:

服务器和4G模块以透传模式相连接,开发板烧录代码,上电,4G模块通电,蓝(电源灯)、黄(模组附着网络灯(SIM))、绿(模组与服务器连接成功)三个指示灯常亮。串口1和电脑通过USB转TTL相连接,并且打开对应串口的串口助手。

当在服务器中发送信息,可通过透传模式将信息传递给4G模组,4G模组接收到信息,通过RX-TX将信息传递给开发板,该信息执行开发板中代码信息,开发板中的串口1接收到信息,所以,该信息可以在串口助手中查看到,并且,对应LED灯状态改变。

本实验,要注意,串口的波特率和4G模组的波特率,可在main函数中使用正确的波特率。

补充:在本实验中,使用花生壳APP可以将我们的一个内网的IP地址,映射成我们的外网IP地址,然后我们的其他外网的ip就可以与该外网进行合法通信,这个过程叫做内网穿透。

外网连接(内网穿透)

内网连接

三、出现的问题

当使用亿佰特时,选择对应的串口号和波特率之后,打开串口,进入配置,显示进入AT指令模式失败原因?

波特率选择的不对,换个波特率试试

相关推荐
梁朝辉3 小时前
STM32H750VBT6中ADCINP与INN什么区别
stm32·单片机·嵌入式硬件
省四收割者4 小时前
一文详解信号完整性(1)
python·嵌入式硬件·数学建模·信息与通信·信号处理·智能硬件
崇山峻岭之间5 小时前
单片机无感FOC驱动之ADC
单片机·嵌入式硬件
Ligocious5 小时前
1.点亮一颗小小的LED
单片机·嵌入式硬件
KaifuZeng9 小时前
通信与接口协议面试八、CAN通信
单片机·嵌入式硬件·面试·通信与接口协议
智源单片机设计10 小时前
基于单片机的直流电机双闭环调速系统设计
单片机·嵌入式硬件
KaifuZeng1 天前
通信与接口协议面试一、基本概念
嵌入式硬件·通信与接口协议
☆cwlulu1 天前
调试排查工具介绍(gdb、strace、Valgrind等)
开发语言·c++·嵌入式硬件·ubuntu
lzqrzpt1 天前
LED驱动电源选型标准与工程应用技术要点解析
python·单片机·嵌入式硬件·物联网
木子单片机1 天前
基于51单片机的音乐彩灯设计
单片机·嵌入式硬件·51单片机·keil