当前位置: 首页 > news >正文

东莞商城网站建设哪家便宜超炫酷网站欣赏

东莞商城网站建设哪家便宜,超炫酷网站欣赏,wordpress自动设置文章第一张,app公司这里写目录标题 下位机与PID调试助手传输的原理代码讲解(基于正点原子)解析数据接受和数据发送的底层函数数据接受数据帧格式环形数组以及怎么找到它的帧头位置crc校验 数据发送数据上传函数 通过前两节文章#xff0c;我已经了解了基本的pid算法#xff0c;现在在完成了电机… 这里写目录标题 下位机与PID调试助手传输的原理代码讲解(基于正点原子)解析数据接受和数据发送的底层函数数据接受数据帧格式环形数组以及怎么找到它的帧头位置crc校验 数据发送数据上传函数 通过前两节文章我已经了解了基本的pid算法现在在完成了电机编码测速pid控制电机转速的前提我们来解析一下下位机是如何pid调试助手进行数据传递的. 下位机与PID调试助手传输的原理 首先用c#写一个PID调试助手然后拟定好传递数据的通信协议然后下位机配置好串口下位机使用串口发送指令给上位机解析(按照通信协议),上位机发送数据下位通过串口接受到上位机传来的指令进行解析。 代码讲解(基于正点原子) 正点原子的代码使F4系列的我修改成了stm32F103ZET6的板子代码 现在我们先来讲一讲函数怎么调用. 首先看到主函数里的程序。 /******************************************************************************************************* file main.c* author 正点原子团队(ALIENTEK)* version V1.0* date 2021-10-16* brief 直流有刷电机速度环PID控制 实验* license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司***************************************************************************************************** attention** 实验平台:正点原子 F407电机开发板* 在线视频:www.yuanzige.com* 技术论坛:www.openedv.com/forum.php* 公司网址:www.alientek.com* 购买地址:openedv.taobao.com******************************************************************************************************/#include ./SYSTEM/sys/sys.h #include ./SYSTEM/usart/usart.h #include ./SYSTEM/delay/delay.h #include ./BSP/LED/led.h #include ./BSP/KEY/key.h #include ./BSP/LCD/lcd.h #include ./BSP/DC_MOTOR/dc_motor.h #include ./BSP/ADC/adc.h #include ./BSP/TIMER/dcmotor_tim.h #include ./BSP/PID/pid.h #include ./DEBUG/debug.hextern uint8_t g_run_flag;void lcd_dis(void);int main(void) {uint8_t key;uint16_t t;uint8_t debug_cmd 0;HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */delay_init(168); /* 延时初始化 */usart_init(115200); /* 串口1初始化用于上位机调试 */led_init(); /* 初始化LED */lcd_init(); /* 初始化LCD */key_init(); /* 初始化按键 */pid_init(); /* 初始化PID参数 */atim_timx_cplm_pwm_init(8400 - 1 , 0); /* 168 000 000 / 1 168 000 000 168Mhz的计数频率计数8400次为50us */dcmotor_init(); /* 初始化电机 */gtim_timx_encoder_chy_init(0XFFFF, 0); /* 编码器定时器初始化不分频直接84M的计数频率 */btim_timx_int_init(1000 - 1 , 84 - 1); /* 基本定时器初始化1ms计数周期 */#if DEBUG_ENABLE /* 开启调试 */debug_init(); /* 初始化调试 */debug_send_motorcode(DC_MOTOR); /* 上传电机类型直流有刷电机 */debug_send_motorstate(IDLE_STATE); /* 上传电机状态空闲 *//* 同步数据选择第1组PID,目标速度地址,P,I,D参数到上位机 */debug_send_initdata(TYPE_PID1, (float *)(g_speed_pid.SetPoint), KP, KI, KD);#endifg_point_color WHITE;g_back_color BLACK;lcd_show_string(10, 10, 200, 16, 16, DcMotor Test, g_point_color);lcd_show_string(10, 30, 200, 16, 16, KEY0:Start forward, g_point_color);lcd_show_string(10, 50, 200, 16, 16, KEY1:Start backward, g_point_color);lcd_show_string(10, 70, 200, 16, 16, KEY2:Stop, g_point_color);while (1){key key_scan(0); /* 按键扫描 */if(key KEY0_PRES) /* 当key0按下 */{g_run_flag 1; /* 标记电机启动 */g_speed_pid.SetPoint 30;if (g_speed_pid.SetPoint 0){dcmotor_stop(); /* 停止则立刻响应 */g_motor_data.motor_pwm 0;motor_pwm_set(g_motor_data.motor_pwm); /* 设置电机方向、转速 */}else{dcmotor_start(); /* 开启电机 */if (g_speed_pid.SetPoint 300) /* 限速 */{g_speed_pid.SetPoint 300;} #if DEBUG_ENABLEdebug_send_motorstate(RUN_STATE); /* 上传电机状态运行 */ #endif}}else if(key KEY1_PRES) /* 当key1按下 */{g_run_flag 1; /* 标记电机启动 */g_speed_pid.SetPoint - 30;if (g_speed_pid.SetPoint 0){dcmotor_stop(); /* 停止则立刻响应 */g_motor_data.motor_pwm 0;motor_pwm_set(g_motor_data.motor_pwm); /* 设置电机方向、转速 */}else{dcmotor_start(); /* 开启电机 */if (g_speed_pid.SetPoint -300) /* 限速 */{g_speed_pid.SetPoint -300;} #if DEBUG_ENABLEdebug_send_motorstate(RUN_STATE); /* 上传电机状态运行 */ #endif}}else if(key KEY2_PRES) /* 当key2按下 */{dcmotor_stop(); /* 停止电机 */pid_init(); /* 重置pid参数 */g_run_flag 0; /* 标记电机停止 */g_motor_data.motor_pwm 0;motor_pwm_set(g_motor_data.motor_pwm); /* 设置电机转向、速度 */#if DEBUG_ENABLEdebug_send_motorstate(BREAKED_STATE); /* 上传电机状态刹车 */debug_send_initdata(TYPE_PID1, (float *)(g_speed_pid.SetPoint), KP, KI, KD); /* 同步数据到上位机 */ #endif}#if DEBUG_ENABLE/* 查询接收PID助手的PID参数 */debug_receive_pid(TYPE_PID1, (float *)g_speed_pid.Proportion,(float *)g_speed_pid.Integral, (float *)g_speed_pid.Derivative);debug_set_point_range(300, -300, 300); /* 设置目标速度范围 */debug_cmd debug_receive_ctrl_code(); /* 读取上位机指令 */if (debug_cmd BREAKED) /* 电机刹车 */{dcmotor_stop(); /* 停止电机 */pid_init(); /* 重置pid参数 */g_run_flag 0; /* 标记电机停止 */g_motor_data.motor_pwm 0;motor_pwm_set(g_motor_data.motor_pwm); /* 设置电机转向、速度 */debug_send_motorstate(BREAKED_STATE); /* 上传电机状态刹车 */debug_send_initdata(TYPE_PID1, (float *)(g_speed_pid.SetPoint), KP, KI, KD);} else if (debug_cmd RUN_CODE) /* 电机运行 */{ dcmotor_start(); /* 开启电机 */g_speed_pid.SetPoint 30; /* 设置目标速度30 RPM */g_run_flag 1; /* 标记电机启动 */debug_send_motorstate(RUN_STATE); /* 上传电机状态运行 */} #endift;if(t % 20 0){lcd_dis(); /* 显示数据 */LED0_TOGGLE(); /*LED0(红灯) 翻转*/ #if DEBUG_ENABLEdebug_send_speed(g_motor_data.speed); /* 发送速度 */ #endif}delay_ms(10);} }/*** brief 数据显示函数* param 无* retval 无*/ void lcd_dis(void) {char buf[32];/* 显示占空比正负号为电机方向 */sprintf(buf, PWM_Duty:%.1f%c , (float)(g_motor_data.motor_pwm * 100 / 8400), %);lcd_show_string(10, 150, 200, 16, 16, buf, g_point_color);/* 设置的目标速度 */sprintf(buf, Set Speed :%3d RPM , (int16_t)g_speed_pid.SetPoint);lcd_show_string(10, 180, 200, 16, 16, buf, g_point_color); /* 电机实际速度 */sprintf(buf, Speed :%3d RPM , (int16_t)g_motor_data.speed);lcd_show_string(10, 210, 200, 16, 16, buf, g_point_color); } #if DEBUG_ENABLE /* 开启调试 */debug_init(); /* 初始化调试 */debug_send_motorcode(DC_MOTOR); /* 上传电机类型直流有刷电机 */debug_send_motorstate(IDLE_STATE); /* 上传电机状态空闲 *//* 同步数据选择第1组PID,目标速度地址,P,I,D参数到上位机 */debug_send_initdata(TYPE_PID1, (float *)(g_speed_pid.SetPoint), KP, KI, KD);#endif首先初始化调试就是将用来存放参数的结构体变量清零。 接着上传下电机类型 上传电机状态 把此时Kp,Ki,Kd的值发给pid调试助手。 上传数据的函数。 这里我只上传了电机的速度差不多200ms上传一次。 发送波形函数 这里我上传实际速度目标速度占空比值每50ms上传一次 这里我上传三个通道 通道1上传实际速度 通道2上传目标速度 通道3上传占空比 接受上位机发送数据函数 这里设定目标范围已经设定目标的变化上限。 读取上位机指令。 判断指令是否是刹车然后执行相关操作。 判断指令是否是运行然后执行相关操作。 在主函数的while循环里一直调用这些函数。 解析数据接受和数据发送的底层函数 数据接受 通过串口来接收上位机发来的数据包(中断接收只要上位机一发送数据就会产生串口中断然后在接受中断回调函数里族逐个字节来接收数据并解析数据。 数据帧格式 /*** brief 上位机数据解析* param *data接收的数据地址* note 利用环形缓冲区来接收数据再存进相应的结构体成员中* retval 无*/ void debug_handle(uint8_t *data) {uint8_t temp[DEBUG_REV_MAX_LEN];uint8_t i;if (debug_rev_p DEBUG_REV_MAX_LEN) /* 超过缓冲区数组最大长度 */{debug_rev_p 0; /* 地址偏移量清零 */}debug_rev_data[debug_rev_p] *(data); /* 取出数据存进数组 */if (*data DEBUG_DATA_END) /* 判断是否收到帧尾 */{if (debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 4) % DEBUG_REV_MAX_LEN] DEBUG_DATA_HEAD) /* 数据包长度为5个字节判断第一个字节是否为帧头 */{for (i 0; i 2; i){temp[i] debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 4 i) % DEBUG_REV_MAX_LEN]; /* 取出帧头、数据类别5个字节的数据包没有数据域 */}#if EN_CRC /* 进行CRC校验 */if (crc16_calc(temp, 2) ((debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 4 2) % DEBUG_REV_MAX_LEN] 8) | \debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 4 3) % DEBUG_REV_MAX_LEN])) #endif{if (debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 4 1) % DEBUG_REV_MAX_LEN] CMD_GET_ALL_DATA) /* 判断数据类别是否为获取全部参数 */{debug_upload_data(g_debug, TYPE_STATUS); /* 发送电机状态 */debug_upload_data(g_debug, TYPE_SPEED); /* 发送速度值 */debug_upload_data(g_debug, TYPE_HAL_ENC); /* 发送霍尔、编码器位置 */debug_upload_data(g_debug, TYPE_VBUS); /* 发送电压 */debug_upload_data(g_debug, TYPE_AMP); /* 发送电流 */debug_upload_data(g_debug, TYPE_TEMP); /* 发送温度 */debug_upload_data(g_debug, TYPE_SUM_LEN); /* 发送总里程 */debug_upload_data(g_debug, TYPE_BEM); /* 发送反电动势 */debug_upload_data(g_debug, TYPE_MOTOR_CODE); /* 发送电机类型 */for (i TYPE_PID1; i TYPE_PID10; i){debug_upload_data(g_debug, i); /* 发送PID参数 */}}}}if (debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 5) % DEBUG_REV_MAX_LEN] DEBUG_DATA_HEAD) /* 数据包长度为6个字节判断第一个字节是否为帧头 */{for (i 0; i 3; i){temp[i] debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 5 i) % DEBUG_REV_MAX_LEN]; /* 取出帧头、数据类别、数据域 */} #if EN_CRC /* 进行CRC校验 */if (crc16_calc(temp, 3) ((debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 5 3) % DEBUG_REV_MAX_LEN] 8) | \debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 5 4) % DEBUG_REV_MAX_LEN])) #endif{switch (debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 5 1) % DEBUG_REV_MAX_LEN]) /* 判断数据类别 */{case CMD_SET_CTR_CODE: /* 下发控制指令 */debug_rev.Ctrl_code debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 5 2) % DEBUG_REV_MAX_LEN];break;case CMD_SET_CTR_MODE: /* 下发控制模式 */debug_rev.Ctrl_mode debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 5 2) % DEBUG_REV_MAX_LEN];break;}}}if (debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 6) % DEBUG_REV_MAX_LEN] DEBUG_DATA_HEAD) /* 数据包长度为7个字节判断第一个字节是否为帧头 */{for (i 0; i 4; i){temp[i] debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 6 i) % DEBUG_REV_MAX_LEN]; /* 取出帧头、数据类别、数据域 */} #if EN_CRC /* 进行CRC校验 */if (crc16_calc(temp, 4) ((debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 6 4) % DEBUG_REV_MAX_LEN] 8) | \debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 6 5) % DEBUG_REV_MAX_LEN])) #endif{switch (debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 6 1) % DEBUG_REV_MAX_LEN]) /* 判断数据类别 */{case CMD_SET_SPEED: /* 设定电机速度 */*(debug_rev.speed) (int16_t)((debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 6 2) % DEBUG_REV_MAX_LEN] 8) | \debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 6 3) % DEBUG_REV_MAX_LEN]);break;case CMD_SET_TORQUE: /* 设定转矩 */*(debug_rev.torque) (debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 6 2) % DEBUG_REV_MAX_LEN] 8) | \debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 6 3) % DEBUG_REV_MAX_LEN];break;}}}if (debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 16) % DEBUG_REV_MAX_LEN] DEBUG_DATA_HEAD) /* 数据包长度为17个字节判断第一个字节是否为帧头 */{for (i 0; i 14; i){temp[i] debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 16 i) % DEBUG_REV_MAX_LEN]; /* 取出帧头、数据类别、数据域 */} #if EN_CRC /* 进行CRC校验 */if (crc16_calc(temp, 14) ((debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 16 14) % DEBUG_REV_MAX_LEN] 8) | \debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 16 15) % DEBUG_REV_MAX_LEN])) #endif{switch (debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 16 1) % DEBUG_REV_MAX_LEN]) /* 判断数据类别 */{case CMD_SET_PID1:case CMD_SET_PID2:case CMD_SET_PID3:case CMD_SET_PID4:case CMD_SET_PID5:case CMD_SET_PID6:case CMD_SET_PID7:case CMD_SET_PID8:case CMD_SET_PID9:case CMD_SET_PID10:for (i 0; i 12; i) /* 接收设定的PID参数 */{g_debug.pid[debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 16 1) % DEBUG_REV_MAX_LEN] - CMD_SET_PID1].pid.pidi8[i] \debug_rev_data[(debug_rev_p DEBUG_REV_MAX_LEN - 16 2 i) % DEBUG_REV_MAX_LEN];}break;}}}}debug_rev_p ; } 首先先来说一下上位机的解析函数 上位机数据的解析函数是用环形数组的形式来存放这样不会产生内存碎片通过串口不断接受数组然后把接受到的数组按照环形的顺序赋予给数值并判断是否是帧尾如果是帧尾则接着判断是几字节的包并且首字节是否是帧头这里四种四节的包分别是5字节6字节7字节17字节。所以可以看到代码里进行了四个if语句判断分别是什么字节并且首字节是否为帧头然后分别进行crc校验如果校验正确则把表示数组类别和数据域的包给取出来然后根据通信协议将参数存放结构体变量进行对应赋值。 四个if语句 环形数组以及怎么找到它的帧头位置 例如数组大小为17的数组当它的地址偏移量到达17的时候则重新从0开始赋值。 我们现在已经知道帧尾的位置了接下来如何找到帧头的位置呢 这就和上面的四个if语句对应上了例如我们要数据包长度为5的帧头 我们就可以用当前的地址偏移量数组长度-数据包长度-1% 数组长度来找到帧头的位置。 crc校验 本例程数据通过crc校验进行验证。 CRC定义  CRC即循环冗余校验码是数据通信领域中最常用的一种查错校验码其特征是信息字段和校验字段的长度可以任意选定。循环冗余检查CRC是一种数据传输检错功能对数据进行多项式计算并将得到的结果附在帧的后面接收设备也执行类似的算法以保证数据传输的正确性和完整性。  取出帧头、数据类别、数据域进行crc校验  代码   数据发送 数据上传函数 构建数组包 先定义一个数组 upload_data[37]为什么是37呢因为最长的数据包是37byte。 判断数据类别并进行指令存储 根据upload_type的值来确定数据类别然后进行把数据域值赋给upload_data数组。 判断是否未数据类别错误如果不是则进行crc校验然后把指令发送给pid调试助手。
http://www.w-s-a.com/news/555752/

相关文章:

  • 网站分几种access做网站数据方法
  • 网站默认图片s001网站建设公司
  • 淘宝的电子商务网站的建设东莞哪里有网站制作公司
  • 西安网站制作怎么联系wordpress登陆界面打开慢
  • 高端工作网站网站推广seo代理
  • 一般找素材都是做哪几个网站呢推广引流工具
  • 必须做网站等级保护html网页设计题库
  • 移动端网站开发 float手机在线建网站
  • 教育网站模板下载做汽车网站开题报告的意义
  • 网站首页做后台链接昌平网站制作
  • 营销型门户网站建设浏览器下载免费大全
  • 快三网站开发推广普通话手抄报内容50字
  • 沈阳专业做网站开发公司asp网站搭建教程
  • 网站建设代码福州小程序开发平台
  • 了解做房产广告的网站手机版官方网站的建设
  • 如何与别的网站做友情链接做网站排名大概要多少钱
  • 东莞市锂电池网站建设HTML5怎么做自适应网站
  • 江苏城乡建设学校网站群晖建立wordpress
  • wordpress导入网站模板seo自学网官网
  • 购物网站服务器带宽北京网站开发周期
  • 同性做视频网站网站怎么添加栏目
  • 新余网站设计seo自学网站
  • 新乡个人网站建设价格wordpress数据插件
  • 你是网站设计有限公司的项目经理网站推广的重要性
  • 网站定制开发怎么写泸州设计公司有哪些
  • 上海网站建设zj kt迅速编程做网站
  • 郑州服装 网站建设网站栏目合理性
  • 平面设计在线网站最新汽油价格调整最新消息
  • 刷单网站建设wordpress缩略图 裁剪
  • 视差 网站泰州公司做网站