ANO V7上位机协议程序(新版加入DMA形式发送接收)
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
传输,USART
的DMA
传输可以看我之前的文章
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 *)¶,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形式发送接收)相关推荐
- ANO匿名上位机V7协议STM32
ANO匿名上位机V7协议&STM32 说明:以下程序为自己编写,若有误欢迎各位指出. 基于ANO匿名V7上位机的通信协议编写的代码 文章目录 ANO匿名上位机V7协议&STM32 前言 ...
- ftp上位机编程c语言,基于USB芯片CY7C68013A的上位机C++程序
标签: 基于USB芯片CY7C68013A的上位机C 基于USB芯片CY7C68013A的上位机C程序 在国标<质量管理体系 基础和术语>GB/T19000-2008/ISO9000:20 ...
- ABB机器人、PLC、C#上位机全套程序 项目用的是ABB蜘蛛机器人
ABB机器人.PLC.C#上位机全套程序 1.项目用的是ABB蜘蛛机器人,六轴用的程序开发都一样 2.上位机与机器人和PLC通讯都是通过以太网总线方式,没有使用传统的IO方式 3.自己写的程序,可提供 ...
- ABB机器人、PLC、C#上位机全套程序,项目用的是ABB蜘蛛机器人,六轴用的程序开发都一样
ABB机器人.PLC.C#上位机全套程序 1.项目用的是ABB蜘蛛机器人,六轴用的程序开发都一样 2.上位机与机器人和PLC通讯都是通过以太网总线方式,没有使用传统的IO方式 3.PLC使用的是200 ...
- 基于VS2015,MFC平台的上位机串口程序搭建详细教程(兼容debug x64、win32 、x86等解决方案平台)
通常在32位编译环境下,我们可以通过插入MFC串口控件(MSCOMM32.OCX)的方式来实现串口通信,但是MSCOMM32.OCX不支持64位编译环境,也就是说,在x64解决方案平台下会报错.为此, ...
- 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 ...
- 污水处理程序西门子Wincc+S7-300污水处理大项目 带西门子Wincc上位机+S7-300程序
污水处理程序西门子Wincc+S7-300污水处理大项目 带西门子Wincc上位机+S7-300程序 污水处理工艺总览包括: 1.进水 2.粗格栅池 3.细隔栅及曝气沉砂池 4.生物除臭池 5.氧化沟 ...
- 西门子Wincc+S7-300污水处理大项目 带西门子Wincc上位机+S7-300程序
西门子Wincc+S7-300污水处理大项目 带西门子Wincc上位机+S7-300程序 污水处理工艺总览包括: 1.进水 2.粗格栅池 3.细隔栅及曝气沉砂池 4.生物除臭池 5.氧化沟 6.配水排 ...
- 选煤厂集控程序 含s7-300plc程序+wincc上位机组态程序
选煤厂集控程序 含s7-300plc程序+wincc上位机组态程序 画面设计美观 程序优化的非常好 编号:4780651684444967unlock
最新文章
- 编写程序,输出所有3位数的水仙花数
- Android初学者之轻松实现语音识别
- GPU Gems1 - 23 景深技术综述
- BeetleX之TCP消息通讯Protobuf/TLS
- 搞不定的C语言--static的作用
- 每天进步一点点——Linux系统时间来处理
- 小米平板5系列将有三个版本:搭载全新骁龙860芯片
- this全面解析(二)
- c多线程并发处理方式_Java并发基础,不怕你看不懂
- Android常用Adapter用例(二)
- Cesium 环境配置笔记(使用node.js 或者WampServer服务器)
- 使用DirectX播放wav声音文件
- tvm relay inline pass的调研
- java经纬度格式_java经纬度格式转换
- 如何查看电脑上曾记录的账号密码
- influxdb java api使用_Influxdb入门使用
- 无人驾驶:无人驾驶感知技术及应用
- qt creator编译qt工程时报错:undefined reference to
- 出版图书二维码,要如何制作呢?
- 基因驱动 CovEx 代码阅读(一)
热门文章
- Mac安装truffle框架时出现✓ Preparing to download box ✖ Downloading Unbox failed! Error: connect的解决方法
- iMeta | 德加合作揭示葛藤菌根真菌的遗传多样性和群落组成
- Android蓝牙搜索连接通信
- 人工蜂群算法(Artificial Bee Colony, ABC)MATALAB代码详细解析
- HashMap源码学习——初探
- 纯前端实现 App Store 卡片展开效果
- 乒乓球重拍轻拍怎么选
- iphone之Info.plist的属性
- 《斯坦福高效睡眠法》读书笔记思维导图版,成年人的睡眠解决法
- oracle中字段类型为date存储数据精确到时分秒的问题