嵌入式的学习之自定义协议

补充: 红色 部分为重要部分;
          绿色 为解析或者补充,如果红色前有绿色,代表文章后有 相关知识
          蓝色 为代码,如果蓝色内部有红色如上;
          紫色 为自我理解与认知不一定正确。
自定义协议
    功能字
    0x01:控制灯
    0x02:获取灯的状态
    0x03发送灯的状态
    0x04:获取DHT11的温度
    0x05:获取DHT11的湿度
    0x06:发送DHT11的温度
    0x07:发送DHT11的湿度
补充部分知识点
异或相同返回0不同返回1
0与任何数异或都等于那个数本身
uint8_t 0~255
static    静态变量在局部定义后等同于全局变量
volatile    可以防止语句被优化省略掉
如何解析协议呢?
我们可以发现这里可以利用状态机,进行状态的存储与使用。
首先检测字节0;
检测成功后检测字节1;(当然如果没有检测到回到起始点检测字节0)(检测成功后要将所有存储在buf中,因为最后要完成校验)
检测数据长度(这里是可能发生改变,包括后面我们可以设置一个变量,对这里的长度进行存储)
…………
最后进行校验
(这里使用了接收的中断,如果不会可以观看串口那期,中断尽可能少操作重复操作可以放在while循环中)
第一步解析:(这里的解析过程是写在接收中断的回调函数中)
 HAL_UART_Receive_IT(&huart1, &rec_data, 1);       //每次在串口1接收一位数时进入中断回调函数
     void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)    //编写 回调函数 参数为进入函数的串口指针,就是使用了那个串口
{
  if(huart ==&huart1)
    {
        rec_buf[rec_index]=rec_data;                   //以buf为数组存储,以index为下标,data为存储在buf中的元素,每来一个填入一个下标前进
        rec_index++;
        switch(frame_state)                                 //检测当前的状态,通过每一个状态进行每一个选项(这里要枚举提前设置每一个状态)
        {
            case FRAME_HEAD_1:                         //头1
                if(rec_buf[0]==0xAA)
                {
                    frame_state=FRAME_HEAD_2;
                }
                else
                {
                rec_index=0;    
                }
                break;
            case FRAME_HEAD_2:                 //头2
                if(rec_buf[1]==0x55)
                {
                    frame_state=FRAME_LENGTH;
                }
                else
                {
                rec_index=0;
                frame_state=FRAME_HEAD_1;
                }
                break;
            case FRAME_LENGTH:             //这里记录了 rec_buf[2]也就是数据位的长度
                rec_len=rec_buf[2];
                frame_state=FRAME_DATA;
                break;
            case FRAME_DATA:                 //这里模拟了数据位的完成,具体内容可以在主函数while里面书写,中断函数尽量不要有太多的运算
            data_len++;
            if( data_len>=rec_buf[2])
            {
                data_len=0;
                frame_state=FRAME_CHECK;
                
            }
            break;
            case FRAME_CHECK:                 //完成后一帧的协议就已经完全的输入其中了但是没有进行校验,也是可以放在主函数中运行,设置的标记代表检测完成
                rec_compelete_flag=1;
                frame_state=FRAME_HEAD_1;
                rec_index=0;
            break;
        }
             HAL_UART_Receive_IT(&huart1, &rec_data, 1);        //再一次进入中断回调函数这是形成循环的关键
    }
}
uint8_t cal_XORSum(uint8_t *buf,uint16_t size)   //这里单独写了一个函数用于校验,不要忘记了在前面声明函数否则无法使用
{
    uint8_t tmp=0;
    for(uint16_t  i=0;i<size;i++)
    {
        tmp^=buf[i];
    }
    return tmp;
}
接下来完成功能(写在主函数中)
    0x01:控制灯:可以通过代码来进行反推协议如果不会可以参考下面的图(标记的判断与复位被我省略了要注意(就是判1与回0))
if(rec_buf[rec_len+3]==cal_XORSum(rec_buf,rec_len+3))
            {
                if(rec_buf[3]==0x01&&rec_buf[4]==0x01)
                {
                    if(rec_buf[5]==0x01)
                    {
                        HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET);
                    }
                    else
                    {
                        HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET);
                    }
                }
                else if(rec_buf[3]==0x01&&rec_buf[4]==0x00)
                {
                    if(rec_buf[5]==0x01)
                    {
                        HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_RESET);
                    }
                    else
                    {
                        HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_SET);
                    }
                }
    0x02:获取灯的状态(这里要和发送灯的状态一起看)(这个过程是电脑对单片机发出指令)
在写完解析后想要获取状态只需对应协议发送向对应的命令即可如:
     AA 55 02 02 00 FF
    AA 55 02 02 01 FE
0x03发送 灯的状态 (这个过程是单片机回复电脑)
if(rec_buf[3]==0x02&&rec_buf[4]==0x00)
                {
                    uint32_t state =0;
                    uint8_t data[7]={0};                                            //这里注意要新建立一个数组用于储存单片机发回来的数据不能使用,电脑向单片机发送数据使用的数组;
                    state=HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_5);
                    data[0]=0xAA;
                    data[1]=0x55;
                    data[2]=0x03;
                    data[3]=0x03;
                    data[4]=0x00;
                    data[5]=!state;
                    data[6]=cal_XORSum(data,data[2]+3);
                     HAL_UART_Transmit(&huart1,data,7,0xFF);        //通过函数将存在data数组中的数据传输到串口1上,注意 不一定一定要连接在电脑上的,其他的设备也是可以使用的。
                }
                else if(rec_buf[3]==0x02&&rec_buf[4]==0x01)
                {
                    uint32_t state =0;
                    uint8_t data[7]={0};
                    state=HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_5);
                    data[0]=0xAA;
                    data[1]=0x55;
                    data[2]=0x03;
                    data[3]=0x03;
                    data[4]=0x01;
                    data[5]=!state;
                    data[6]=cal_XORSum(data,data[2]+3);
                     HAL_UART_Transmit(&huart1,data,7,0xFF);
                }
与上同理:
AA 55 01 04 FA
AA 55 01 05 FB
湿度与温度    (当然如果想要完成此功能需要导入DHT11的驱动前期 嵌入式的学习之DHT11-CSDN博客是有的,而且导入后不要忘记初始化)
if(rec_buf[3]==0x04)
                {
                    uint8_t data[7]={0};
                 DHT11_Read(&shidu,&wendu);
                    data[0]=0xAA;
                    data[1]=0x55;
                    data[2]=0x03;
                    data[3]=0x06;
                    data[4]=shidu;
                    data[5]=0x00;
                    data[6]=cal_XORSum(data,data[2]+3);
                    HAL_UART_Transmit(&huart1,data,7,0xFF);
                }
                else if(rec_buf[3]==0x05)
                {
                    uint8_t data[7]={0};
                    DHT11_Read(&shidu,&wendu);
                    data[0]=0xAA;
                    data[1]=0x55;
                    data[2]=0x03;
                    data[3]=0x07;
                    wendu=wendu*100;
                    data[4]=(int)wendu/100;
                    data[5]=(int)wendu%100;
                    data[6]=cal_XORSum(data,data[2]+3);
                    HAL_UART_Transmit(&huart1,data,7,0xFF);
                }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值