ANO V7上位机协议程序(新版加入DMA形式发送接收)

文章目录

  • ANO V7上位机协议程序(新版加入DMA形式发送接收)
  • 前言
  • 一、程序说明
    • 1,移植说明
    • 2,使用说明
      • a,发送数据
      • b,接收参数&命令
  • 二,程序源码
    • 1,`MyAno.c`
    • 2,`MyAno.h`

前言

前言:本版本是基于之前那个版本进行完善优化,加入了DMA发送,能够很好的减缓CPU的负担,并且可以保证程序的时序不会出问题,因为DMA传输和CPU的执行是并行的。


提示:ANO V7上位机的用法与介绍请看我之前的文章
ANO匿名上位机V7协议&STM32
所以,本文只是对协议程序进行说明

一、程序说明

1,移植说明

程序在以前的基础上进行了优化,你们移植起来也较为轻松
MyAno.h中只需修改两个宏定义,一个是是否使用DMA传输,USARTDMA传输可以看我之前的文章
STM32F4配置USART(DMA形式传输)


以下函数为用户可重写函数

2,使用说明

a,发送数据

用户需在串口初始化后调用Ano_Init函数

然后根据需要调用对应的发送函数

以下函数是用户打印Log信息的时候使用的

会打印在上位机的坐下角

提示:若不知道如何使用函数请查看示例函数

b,接收参数&命令

需要把以下函数放进串口回调函数中

串口回调函数的写法如下

注:在读取参数的时候会导致读取校验失败,所以我们需要在发送数据的时候加上一个判断,如下:

if(MPara.OrderState == 0)  //接收命令结束
{//发送数据代码
}

二,程序源码

1,MyAno.c

#include "MyAno.h"
#include "string.h"
#include "usart.h"
#include "math.h"_ano MyAno = {0};           //发送的数据
_Para MPara = {0};         //参数/**     *   函数名:    参数初始化*  形   参:  无*  返回值:    无
**/
void Ano_Init(void)
{MyAno.Head = 0xAA;MyAno.Addr = 0xFF;MyAno.Lenth = 0;
}/**    * 函数名:  发送ID对应的参数* 形    参:  Id - 参数ID*          para - 参数数据*    返回值:    无
**/
static void SendParaData(uint8_t Id,int32_t para)
{Ano_Set_Mdata(0xE2,(uint16_t *)&Id,2,1);   //加载IDAno_Set_Mdata(0xE2,(int32_t *)&para,4,2); //加载参数数据Ano_SendMdata();    //发送数据
}/*** 函数名:  发送数据校验帧0x00* 形  参:  id - 帧的ID   *           sumcheck 和校验数据*             addcheck 附加校验数据* 返回值:无
**/
static void SendCheckAnalysis(uint8_t id,uint8_t *sumcheck,uint8_t *addcheck)
{Ano_Set_Mdata(0x00,(uint8_t *)&id,1,1);Ano_Set_Mdata(0x00,(uint8_t *)sumcheck,1,2);Ano_Set_Mdata(0x00,(uint8_t *)addcheck,1,3);Ano_SendMdata();
}/**    *   函数名:    接收数据校验检测*   形   参:  _da数据*  返回值:    1校验成功   0校验失败
**/
static uint8_t Receive_CheckData(uint8_t *_da)
{uint8_t i = 0;uint8_t sumcheck = 0,addcheck = 0;for(i = 0;i < _da[3] + 4;i++){sumcheck += _da[i];addcheck += sumcheck;}  if((sumcheck == _da[_da[3] + 4]) && (addcheck == _da[_da[3] + 5]))        //校验通过return 1;elsereturn 0;
}/**    *   函数名:    发送数据和校验&附加校验计算* 形   参:  ano结构体* 返回值:    1->校验成功 0->校验失败
**/
static uint8_t Send_CheckData(_ano *ano)
{uint8_t i = 0;uint8_t sumcheck = 0,addcheck = 0;for(i = 0;i < ano->Lenth + 4;i++){sumcheck += ano->SendBuff[i];addcheck += sumcheck;}  memcpy(ano->SendBuff + 4 + ano->Lenth,(uint8_t*)&sumcheck,sizeof(sumcheck));memcpy(ano->SendBuff + 5 + ano->Lenth,(uint8_t*)&addcheck,sizeof(addcheck));/* 其中 ano->SendBuff[3] 表示数据长度 */if(sumcheck == ano->SendBuff[ano->SendBuff[3] + 4] && addcheck == ano->SendBuff[ano->SendBuff[3] + 5])return 1;elsereturn 0;
}/*** 函数名:   控制指令* 形 参:   _Ord命令* 返回值: 无
**/
__weak void ControlOrder(uint8_t _Ord)
{switch (_Ord)  //命令{case Stop:         //程序停止Ano_SendString("程序停止运行!\r\n",Color_Red);break;case Operation:       //运行程序Ano_SendString("程序开始运行!\r\n",Color_Green);break;case Store:         //储存参数Ano_SendString("参数储存成功!\r\n",Color_Green);break;}
}/*** 函数名:   参数回传设置* 形 参: _id参数的ID* 返回值:   无
**/
__weak void ParaOfReturn_Set(uint16_t _id)
{switch (_id){case 1:       SendParaData((uint8_t )_id,(int32_t)HWTYPE);    break;  //参数回传硬件版本(此处借用拓空者)case PID_1_P:  SendParaData((uint8_t )_id,(int32_t)MPara.PID_Par1_P);  break;  case PID_1_I:   SendParaData((uint8_t )_id,(int32_t)MPara.PID_Par1_I);  break;  case PID_1_D:   SendParaData((uint8_t )_id,(int32_t)MPara.PID_Par1_D);  break;  //参数回传(第一组PID)case PID_2_P:   SendParaData((uint8_t )_id,(int32_t)MPara.PID_Par2_P);  break;  case PID_2_I:   SendParaData((uint8_t )_id,(int32_t)MPara.PID_Par2_I);  break;  case PID_2_D:   SendParaData((uint8_t )_id,(int32_t)MPara.PID_Par2_D);  break;  //参数回传(第二组PID)case PID_3_P:   SendParaData((uint8_t )_id,(int32_t)MPara.PID_Par3_P);  break;  case PID_3_I:   SendParaData((uint8_t )_id,(int32_t)MPara.PID_Par3_I);  break;  case PID_3_D:   SendParaData((uint8_t )_id,(int32_t)MPara.PID_Par3_D);  break;  //参数回传(第三组PID)default: SendParaData((uint8_t )_id,(int32_t)0x00); break;  //若为其他参数则返回0    }
}/*** 函数名:   参数数据读取设置* 形 参:   _id参数的ID*           _val参数数据* 返回值:   无
**/
__weak void ParaRead_Set(uint16_t _id,int32_t _val)
{switch (_id){case PID_1_P: MPara.PID_Par1_P = _val;   break;  //参数回传硬件版本(此处借用拓空者)case PID_1_I:  MPara.PID_Par1_I = _val;   break;  //参数回传硬件版本(此处借用拓空者)case PID_1_D:  MPara.PID_Par1_D = _val;   break;  //参数回传硬件版本(此处借用拓空者)case PID_2_P:  MPara.PID_Par2_P = _val;   break;  //参数回传硬件版本(此处借用拓空者)case PID_2_I:  MPara.PID_Par2_I = _val;   break;  //参数回传硬件版本(此处借用拓空者)case PID_2_D:  MPara.PID_Par2_D = _val;   break;  //参数回传硬件版本(此处借用拓空者)case PID_3_P:  MPara.PID_Par3_P = _val;   break;  //参数回传硬件版本(此处借用拓空者)case PID_3_I:  MPara.PID_Par3_I = _val;   break;  //参数回传硬件版本(此处借用拓空者)case PID_3_D:  MPara.PID_Par3_D = _val;   break;  //参数回传硬件版本(此处借用拓空者)}
}/**    *   函数名:    接收数据解析* 形   参:  _da数据(需为完整的一帧数据)*   返回值:    无
**/
void Ano_DataAnalysis(uint8_t *_da)
{uint16_t HeadID = 0;int32_t DataVal = 0;MPara.OrderState = 1;   //在接收命令if(_da[0] == 0xAA && (_da[1] == 0xFF || _da[1] == 0x05))   //判断帧头、和目标地址{if(_da[2] == 0xE0)   //判断功能码(命令帧){if(_da[4] == 0x10 && _da[5] == 0x00)     //判断CID和CMD0ControlOrder(_da[6]);   //控制指令(通过CMD1来控制程序)SendCheckAnalysis((uint8_t )0xE0,(uint8_t *)&(_da[_da[3] + 4]),(uint8_t *)&(_da[_da[3] + 5]));   //回传数据校验帧MPara.OrderState = 0; //命令回传结束}else if(_da[2] == 0xE1)  //判断功能码(读参数){if(Receive_CheckData(_da)){HeadID = (uint8_t)(_da[4] + (_da[5] << 8));ParaOfReturn_Set(HeadID);  //参数回传MPara.OrderState = 0;    //命令回传结束}}else if(_da[2] == 0xE2) //判断功能码(写参数){if(Receive_CheckData(_da)){HeadID = (uint8_t)(_da[4] + (_da[5] << 8));       //(*(uint16_t*)(&_da[4]))DataVal = *(int32_t*)(&_da[6]);ParaRead_Set(HeadID,DataVal);  //参数数据读取设置SendCheckAnalysis((uint8_t )0xE2,(uint8_t *)&(_da[_da[3] + 4]),(uint8_t *)&(_da[_da[3] + 5]));  //回传数据校验帧MPara.OrderState = 0; //命令回传结束}}}
}/**    *   函数名:    多数据配置函数(结合Ano_SendMdata多数据发送函数使用)*    形   参:  id->功能码(0xF1-0xFA) *data->发送的数据 len->数据长度(sizeof) num->用于指示第几个数据(可去除)*    返回值:    无
**/
void Ano_Set_Mdata(uint8_t id,void *data,uint8_t len,uint8_t num)
{MyAno.ID = id;memcpy(MyAno.SendBuff,(uint8_t*)&MyAno,3);memcpy(MyAno.SendBuff + 4 + MyAno.Lenth,(uint8_t*)data,len);MyAno.Lenth += len;memcpy(MyAno.SendBuff + 3,(uint8_t*)&MyAno.Lenth,1);
}/**    *   函数名:    多数据发送(结合Ano_Set_Mdata多数据配置函数使用)*  形   参:  id->功能码(0xF1-0xFA) *data->发送的数据 len->数据长度(sizeof) num->用于指示第几个数据(可去除)*    返回值:    无
**/
void Ano_SendMdata(void)
{uint8_t check;check = Send_CheckData(&MyAno);if(check){#if USER_DMA_USART //使用DMA形式HAL_UART_Transmit_DMA(&usart,(uint8_t*)&MyAno.SendBuff,MyAno.Lenth + 6);  //使用DMA形式#else  //未使用DMA形式HAL_UART_Transmit(&usart,MyAno.SendBuff,MyAno.Lenth + 6,0xFFFF);     //未使用DMA形式USARTmemset(MyAno.SendBuff,0,sizeof(MyAno.SendBuff));MyAno.Lenth = 0;#endif}else{memset(MyAno.SendBuff,0,sizeof(MyAno.SendBuff));MyAno.Lenth = 0;}
}/**    *   函数名:    发送数据函数*     形   参:  id->功能码(0xF1-0xFA) *Data->发送的数据 lenth->数据长度(sizeof)*   返回值:    无
**/
void Ano_Send_Data(uint8_t id, void *Data, uint8_t lenth)   //发送函数
{static uint8_t check;MyAno.ID = id;MyAno.Lenth = lenth;memcpy(MyAno.SendBuff,(uint8_t*)&MyAno,4);memcpy(MyAno.SendBuff + 4,(uint8_t*)Data,lenth);check = Send_CheckData(&MyAno);if(check)  //如果校验成功则发送数据,校验失败就丢弃此包{#if USER_DMA_USART   //使用DMA形式HAL_UART_Transmit_DMA(&usart,MyAno.SendBuff,MyAno.Lenth + 6); //使用DMA形式#else  //未使用DMA形式HAL_UART_Transmit(&usart,MyAno.SendBuff,MyAno.Lenth + 6,0xFFFF); //未使用DMA形式USART#endif}
}/*** 函数名:   发送LOGO信息* 形 参:   字符串\数字* 返回值: 无
**/
void Ano_SendString(const char *str,uint8_t color)
{uint8_t i = 0;Ano_Set_Mdata(0xA0,(uint8_t*)&color,1,1);   //加载颜色数据while (*(str + i) != '\0')      //判断结束位{Ano_Set_Mdata(0xA0,(uint8_t*)(str+i++),1,2); //加载字符串数据}Ano_SendMdata();  //发送数据
}/*** 函数名:   发送LOGO信息+数据信息* 形 参: 字符串\数字* 返回值: 无
**/
void Ano_SendStringVal(const char *str,int32_t Val)
{uint8_t i = 0;Ano_Set_Mdata(0xA0,(int32_t*)&Val,4,1); //加载数据信息while (*(str + i) != '\0')      //判断结束位{Ano_Set_Mdata(0xA1,(uint8_t*)(str+i++),1,2); //加载字符串数据}Ano_SendMdata();  //发送数据
}int16_t Ano_Show_Sin(float x)  //SIN函数
{return 100*sin(2*x);
}float Ano_Show_Cos(float x)    //COS函数
{return 100*cos(2*x);
}float Ano_Show_SQU(float x)    //方波
{if(x > 0 && x < 3.14f)return 10;elsereturn -10;
}void Show_Test(void)   //测试显示
{   int16_t y1,y2,y3;uint8_t nul = 0;static float x = 0;x += 0.01f;if(x > 3.14f)x = -3.14f;y1 = Ano_Show_Sin(x);       //数据*10发送y2 = Ano_Show_Cos(x);     //数据*10发送y3 = Ano_Show_SQU(x);Ano_Set_Mdata(0xF1,(int16_t*)&y1,sizeof(y1),1);Ano_Set_Mdata(0xF1,(int16_t*)&y2,sizeof(y2),2);Ano_Set_Mdata(0xF1,(int16_t*)&y3,sizeof(y3),3);Ano_Set_Mdata(0xF1,(uint8_t*)&nul,sizeof(nul),4);       //加载数据到对应的数据位Ano_SendMdata();   //发送数据
}#if USER_DMA_USART //使用DMA形式
//开启发送中断,等待发送结束,发送结束后把数组进行清零
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == usart.Instance) //判断是串口几产生的发送中断{memset(MyAno.SendBuff,0,sizeof(MyAno.SendBuff));    //清零数组MyAno.Lenth = 0;}
}
#endif

2,MyAno.h

#ifndef __MYANO_H
#define __MYANO_H#include "stm32f4xx_hal.h"
#include "usart.h"#define USER_DMA_USART  1       //使用DMA发送接收数据(0为不使用DMA)#define usart huart1           //使用串口一#define Color_Black      0
#define Color_Red       1
#define Color_Green     2   //Log打印颜色enum AnoID
{Stop = 0x00,      //停止运行Operation,            //开始运行Store,                //储存HWTYPE = 0x05, //硬件种类PID_1_P = 11,PID_1_I,PID_1_D,        //第一组PIDPID_2_P,PID_2_I,PID_2_D,        //第二组PIDPID_3_P,PID_3_I,PID_3_D         //第三组PID
};typedef struct
{uint8_t Head;uint8_t Addr;uint8_t ID;uint8_t Lenth;uint8_t SendBuff[1024]; //发送缓存数组uint8_t ReceiveBuf[10]; //接收缓存数组
}_ano;typedef struct
{uint8_t OrderState;        //命令接收状态uint16_t PID_Par1_P;uint16_t PID_Par1_I;uint16_t PID_Par1_D;    //第一组PIDuint16_t PID_Par2_P;uint16_t PID_Par2_I;uint16_t PID_Par2_D;    //第二组PIDuint16_t PID_Par3_P;uint16_t PID_Par3_I;uint16_t PID_Par3_D;    //第三组PID/* data */
}_Para;extern _ano MyAno;       //声明外部变量
extern _Para MPara;     //参数/****** 用户不可调用函数 ******/
static void SendParaData(uint8_t Id,int32_t para);      //发送ID对应的参数
static void SendCheckAnalysis(uint8_t id,uint8_t *sumcheck,uint8_t *addcheck);      //发送数据校验帧0x00
static uint8_t Receive_CheckData(uint8_t *_da);     //接收数据校验检测
static uint8_t Send_CheckData(_ano *ano);           //发送数据和校验&附加校验计算/****** 用户可调用函数 ******/
void Ano_Init(void);                                                //参数初始化
void Ano_Send_Data(uint8_t id, void *Data, uint8_t lenth);          //发送数据函数
void Ano_Set_Mdata(uint8_t id,void *data,uint8_t len,uint8_t num);  //多数据配置
void Ano_SendMdata(void);                                           //多数据发送
void Ano_DataAnalysis(uint8_t *_da);                                //接收数据解析(放串口回调函数里面)
void Ano_SendString(const char *str,uint8_t color);                 //发送字符串
void Ano_SendStringVal(const char *str,int32_t Val);                //发送字符串+数据值void Show_Test(void);   //测试显示函数/****** 用户可调用&重写函数 ******/
__weak void ControlOrder(uint8_t _Ord);                 //控制指令
__weak void ParaOfReturn_Set(uint16_t _id);             //参数回传设置
__weak void ParaRead_Set(uint16_t _id,int32_t _val);    //参数数据读取设置#endif 

下载链接: ANO_V7_MyAno.zip

ANO V7上位机协议程序(新版加入DMA形式发送接收)相关推荐

  1. ANO匿名上位机V7协议STM32

    ANO匿名上位机V7协议&STM32 说明:以下程序为自己编写,若有误欢迎各位指出. 基于ANO匿名V7上位机的通信协议编写的代码 文章目录 ANO匿名上位机V7协议&STM32 前言 ...

  2. ftp上位机编程c语言,基于USB芯片CY7C68013A的上位机C++程序

    标签: 基于USB芯片CY7C68013A的上位机C 基于USB芯片CY7C68013A的上位机C程序 在国标<质量管理体系 基础和术语>GB/T19000-2008/ISO9000:20 ...

  3. ABB机器人、PLC、C#上位机全套程序 项目用的是ABB蜘蛛机器人

    ABB机器人.PLC.C#上位机全套程序 1.项目用的是ABB蜘蛛机器人,六轴用的程序开发都一样 2.上位机与机器人和PLC通讯都是通过以太网总线方式,没有使用传统的IO方式 3.自己写的程序,可提供 ...

  4. ABB机器人、PLC、C#上位机全套程序,项目用的是ABB蜘蛛机器人,六轴用的程序开发都一样

    ABB机器人.PLC.C#上位机全套程序 1.项目用的是ABB蜘蛛机器人,六轴用的程序开发都一样 2.上位机与机器人和PLC通讯都是通过以太网总线方式,没有使用传统的IO方式 3.PLC使用的是200 ...

  5. 基于VS2015,MFC平台的上位机串口程序搭建详细教程(兼容debug x64、win32 、x86等解决方案平台)

    通常在32位编译环境下,我们可以通过插入MFC串口控件(MSCOMM32.OCX)的方式来实现串口通信,但是MSCOMM32.OCX不支持64位编译环境,也就是说,在x64解决方案平台下会报错.为此, ...

  6. PXIe板卡 原理图PDF PCB源文件 K7 PCIe板卡 FMC板卡 XC7K325T 标准3U尺寸 提供PCIe,DDR,上位机应用程序等源码例程原理图PDF PCB源文件

    PXIe板卡 K7 PCIe板卡 FMC板卡 XC7K325T 标准3U尺寸 64bit DDR3(2GByte) 提供PCIe,DDR,上位机应用程序等源码例程 原理图PDF PCB源文件 ID:6 ...

  7. 污水处理程序西门子Wincc+S7-300污水处理大项目 带西门子Wincc上位机+S7-300程序

    污水处理程序西门子Wincc+S7-300污水处理大项目 带西门子Wincc上位机+S7-300程序 污水处理工艺总览包括: 1.进水 2.粗格栅池 3.细隔栅及曝气沉砂池 4.生物除臭池 5.氧化沟 ...

  8. 西门子Wincc+S7-300污水处理大项目 带西门子Wincc上位机+S7-300程序

    西门子Wincc+S7-300污水处理大项目 带西门子Wincc上位机+S7-300程序 污水处理工艺总览包括: 1.进水 2.粗格栅池 3.细隔栅及曝气沉砂池 4.生物除臭池 5.氧化沟 6.配水排 ...

  9. 选煤厂集控程序 含s7-300plc程序+wincc上位机组态程序

    选煤厂集控程序 含s7-300plc程序+wincc上位机组态程序 画面设计美观 程序优化的非常好 编号:4780651684444967unlock

最新文章

  1. 编写程序,输出所有3位数的水仙花数
  2. Android初学者之轻松实现语音识别
  3. GPU Gems1 - 23 景深技术综述
  4. BeetleX之TCP消息通讯Protobuf/TLS
  5. 搞不定的C语言--static的作用
  6. 每天进步一点点——Linux系统时间来处理
  7. 小米平板5系列将有三个版本:搭载全新骁龙860芯片
  8. this全面解析(二)
  9. c多线程并发处理方式_Java并发基础,不怕你看不懂
  10. Android常用Adapter用例(二)
  11. Cesium 环境配置笔记(使用node.js 或者WampServer服务器)
  12. 使用DirectX播放wav声音文件
  13. tvm relay inline pass的调研
  14. java经纬度格式_java经纬度格式转换
  15. 如何查看电脑上曾记录的账号密码
  16. influxdb java api使用_Influxdb入门使用
  17. 无人驾驶:无人驾驶感知技术及应用
  18. qt creator编译qt工程时报错:undefined reference to
  19. 出版图书二维码,要如何制作呢?
  20. 基因驱动 CovEx 代码阅读(一)

热门文章

  1. Mac安装truffle框架时出现✓ Preparing to download box ✖ Downloading Unbox failed! Error: connect的解决方法
  2. iMeta | 德加合作揭示葛藤菌根真菌的遗传多样性和群落组成
  3. Android蓝牙搜索连接通信
  4. 人工蜂群算法(Artificial Bee Colony, ABC)MATALAB代码详细解析
  5. HashMap源码学习——初探
  6. 纯前端实现 App Store 卡片展开效果
  7. 乒乓球重拍轻拍怎么选
  8. iphone之Info.plist的属性
  9. 《斯坦福高效睡眠法》读书笔记思维导图版,成年人的睡眠解决法
  10. oracle中字段类型为date存储数据精确到时分秒的问题