- #include "main.h"
- #include "math.h"
- /************************************* 第二部分 电压电流温度采集 **********************************************/
- uint16_t g_adc_val[ADC_CH_NUM]; /*ADC平均值存放数组*/
- PID_TypeDef g_current_pid; /* 电流环PID参数结构体 */
- /*
- Rt = Rp *exp(B*(1/T1-1/T2))
- Rt 是热敏电阻在T1温度下的阻值;
- Rp是热敏电阻在T2常温下的标称阻值;
- exp是e的n次方,e是自然常数,就是自然对数的底数,近似等于 2.7182818;
- B值是热敏电阻的重要参数,教程中用到的热敏电阻B值为3380;
- 这里T1和T2指的是开尔文温度,T2是常温25℃,即(273.15+25)K
- T1就是所求的温度
- */
- const float Rp = 10000.0f; /* 10K */
- const float T2 = (273.15f + 25.0f); /* T2 */
- const float Bx = 3380.0f; /* B */
- const float Ka = 273.15f;
- Motor_TypeDef g_motor_data; /*电机参数变量*/
- ENCODE_TypeDef g_encode; /*编码器参数变量*/
- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] 计算温度值
- * @param para: 温度采集对应ADC通道的值(已滤波)
- * [url=home.php?mod=space&uid=536309]@NOTE[/url] 计算温度分为两步:
- 1.根据ADC采集到的值计算当前对应的Rt
- 2.根据Rt计算对应的温度值
- * @retval 温度值
- */
- float get_temp(uint16_t para)
- {
- float Rt;
- float temp;
-
- /*
- 第一步:
- Rt = 3.3 * 4700 / VTEMP - 4700 ,其中VTEMP就是温度检测通道采集回来的电压值,VTEMP = ADC值* 3.3/4096
- 由此我们可以计算出当前Rt的值:Rt = 3.3f * 4700.0f / (para * 3.3f / 4096.0f ) - 4700.0f;
- */
-
- Rt = 3.3f * 4700.0f / (para * 3.3f / 4096.0f ) - 4700.0f; /* 根据当前ADC值计算出Rt的值 */
- /*
- 第二步:
- 根据当前Rt的值来计算对应温度值:Rt = Rp *exp(B*(1/T1-1/T2))
- */
-
- temp = Rt / Rp; /* 解出exp(B*(1/T1-1/T2)) ,即temp = exp(B*(1/T1-1/T2)) */
- temp = log(temp); /* 解出B*(1/T1-1/T2) ,即temp = B*(1/T1-1/T2) */
- temp /= Bx; /* 解出1/T1-1/T2 ,即temp = 1/T1-1/T2 */
- temp += (1.0f / T2); /* 解出1/T1 ,即temp = 1/T1 */
- temp = 1.0f / (temp); /* 解出T1 ,即temp = T1 */
- temp -= Ka; /* 计算T1对应的摄氏度 */
- return temp; /* 返回温度值 */
- }
- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] 计算ADC的平均值(滤波)
- * @param * p :存放ADC值的指针地址
- * [url=home.php?mod=space&uid=536309]@NOTE[/url] 此函数对电压、温度、电流对应的ADC值进行滤波,
- * p[0]-p[2]对应的分别是电压、温度和电流
- * @retval 无
- */
- void calc_adc_val(uint16_t * adcdata)
- {
- uint32_t temp[3] = {0,0,0};
- uint16_t i;
- for(i=0;i<ADC_COLL;i++) /* 循环ADC_COLL次取值,累加 */
- {
- temp[0] += adcdata[0+i*ADC_CH_NUM];
- temp[1] += adcdata[1+i*ADC_CH_NUM];
- temp[2] += adcdata[2+i*ADC_CH_NUM];
- }
- temp[0] /= ADC_COLL; /* 取平均值 */
- temp[1] /= ADC_COLL;
- temp[2] /= ADC_COLL;
-
- g_adc_val[0] = temp[0]; /* 存入电压ADC通道平均值 */
- g_adc_val[1] = temp[1]; /* 存入温度ADC通道平均值 */
- g_adc_val[2] = temp[2]; /* 存入电流ADC通道平均值 */
- }
- uint8_t current_flag =0;
- void get_Motor_value(uint16_t * adcdata)
- {
- #define CURRENT_NUM 4
- #define INIT_CURRENT_NUM 5
- float temp_current=0.0;
- static float adc_current = 0;
- static float init_adc_current = 0;
- static uint8_t current_count1 =0,current_count2 =0;
-
- current_count1++;
- calc_adc_val(adcdata);
- adc_current += g_adc_val[2]; /* 取出电流通道对应的ADC值进行累计 */
-
- if(current_count1 >= CURRENT_NUM)/* 累计15次 */
- {
- adc_current = (float)(adc_current / current_count1); /* 取平均值 */
- if(current_count2 <= INIT_CURRENT_NUM)
- {
- current_count2++;
- init_adc_current += adc_current; /* 对平均值累计求和 */
- if(current_count2 == INIT_CURRENT_NUM)
- {
- init_adc_current = (float)(init_adc_current/current_count2); /* 存储初始ADC值 */
- current_count2 = INIT_CURRENT_NUM+1;
- current_flag =1;
-
- }
- }
- if(current_count2 >= (INIT_CURRENT_NUM+1))
- {
-
- temp_current= ((adc_current - init_adc_current) *ADC2CURT);
- // g_motor_data.current = temp_current;
- FirstOrderRC_LPF(g_motor_data.current,temp_current,0.40);
- //g_motor_data.current = (float)((g_motor_data.current * (float)0.60) + ((float)0.40 * temp_current)); /* 一阶低通滤波 */
-
- if(g_motor_data.current <=20)
- {
- g_motor_data.current=0.0;
- }
- }
- adc_current=0;
- current_count1=0;
- }
- }
- /************************************* 第三部分 编码器测速 ****************************************************/
- void speed_computer(int32_t encode_now, uint8_t ms)
- {
- uint8_t i = 0, j = 0;
- float temp = 0.0;
- static uint8_t sp_count = 0, k = 0;
- static float speed_arr[10] = {0.0}; /* 存储速度进行滤波运算 */
- if (sp_count == ms) /* 计算一次速度 */
- {
- /* 计算电机转速
- 第一步 :计算ms毫秒内计数变化量
- 第二步 ;计算1min内计数变化量:g_encode.speed * ((1000 / ms) * 60 ,
- 第三步 :除以编码器旋转一圈的计数次数(倍频倍数 * 编码器分辨率)
- 第四步 :除以减速比即可得出电机转速
- */
- g_encode.encode_now = encode_now; /* 取出编码器当前计数值 */
- g_encode.speed = (g_encode.encode_now - g_encode.encode_old); /* 计算编码器计数值的变化量 */
-
- speed_arr[k++] = (float)(g_encode.speed * ((1000 / ms) * 60.0) / REDUCTION_RATIO / ROTO_RATIO ); /* 保存电机转速 */
-
- g_encode.encode_old = g_encode.encode_now; /* 保存当前编码器的值 */
- /* 累计10次速度值,后续进行滤波*/
- if (k == 10)
- {
- for (i = 10; i >= 1; i--) /* 冒泡排序*/
- {
- for (j = 0; j < (i - 1); j++)
- {
- if (speed_arr[j] > speed_arr[j + 1]) /* 数值比较 */
- {
- temp = speed_arr[j]; /* 数值换位 */
- speed_arr[j] = speed_arr[j + 1];
- speed_arr[j + 1] = temp;
- }
- }
- }
-
- temp = 0.0;
-
- for (i = 2; i < 8; i++) /* 去除两边高低数据 */
- {
- temp += speed_arr[i]; /* 将中间数值累加 */
- }
-
- temp = (float)(temp / 6); /*求速度平均值*/
-
- /* 一阶低通滤波
- * 公式为:Y(n)= qX(n) + (1-q)Y(n-1)
- * 其中X(n)为本次采样值;Y(n-1)为上次滤波输出值;Y(n)为本次滤波输出值,q为滤波系数
- * q值越小则上一次输出对本次输出影响越大,整体曲线越平稳,但是对于速度变化的响应也会越慢
- */
- g_motor_data.speed = (float)( ((float)0.48 * temp) + (g_motor_data.speed * (float)0.52) );
- k = 0;
- }
- sp_count = 0;
- }
- sp_count ++;
- }
- uint8_t g_run_flag = 0;
- int32_t motor_pwm = 0;
- atk_debug_data_rev get_atk_data;
- void DCMotor_App(void)
- {
- static uint8_t key=0;
- get_atkdebug(&get_atk_data);
- key=key_scan(0);
- if(key == KEY0_PRES)
- {
- TurnTogLed(LED1);
- g_current_pid.SetPoint +=50;
- g_run_flag = 1;
- if (g_current_pid.SetPoint == 0)
- {
- DC_Motor_Stop(MOTOR_1); /* 停止则立刻响应 */
- g_motor_data.motor_pwm = 0;
- Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1); /* 设置电机转速 */
- }
- else
- {
- DC_Motor_Start(MOTOR_1);
- if(g_current_pid.SetPoint >= 250)
- {
- g_current_pid.SetPoint =250;
- }
- atk_debug_send_motorstate(RUN_STATE); /* 上传电机状态(运行) */
- //Motor_PWM_Set(g_current_pid.SetPoint,MOTOR_1);
- }
- }
- else if(key == KEY1_PRES) {
- TurnTogLed(LED1);
- if (g_current_pid.SetPoint == 0)
- {
- DC_Motor_Stop(MOTOR_1); /* 停止则立刻响应 */
- g_motor_data.motor_pwm = 0;
- DC_Motor_Speed(g_motor_data.motor_pwm,MOTOR_1); /* 设置电机转速 */
- }
- else
- {
- }
- }
- else if(key == KEY2_PRES)
- {
- DC_Motor_Stop(MOTOR_1);
- g_run_flag = 0; /* 标记电机停止 */
- g_motor_data.motor_pwm = 0;
- Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1); /* 设置电机转向、速度 */
- pid_init();
- atk_debug_send_motorstate(BREAKED_STATE); /* 上传电机状态(刹车) */
- atk_debug_send_initdata(TYPE_PID1, (float *)(&g_current_pid.SetPoint), KP, KI, KD); /* 同步数据到上位机 */
- }
- }
- void DCMotor_Value(void)
- {
- static uint16_t g_time =0;
- int32_t motor_pwm_temp = 0;
-
- if(current_flag == 0 )
- return;
-
-
- /* 获取编码器值,用于计算速度 */
- get_EncodeValue(5); /* 中位平均值滤除编码器抖动数据,5ms计算一次速度*/
-
- if(g_time % 499 ==0)
- {
-
- g_motor_data.volatage = g_adc_val[0]*ADC2VBUS;
- atk_debug_send_valtage(g_motor_data.volatage );
- __NOP();__NOP();__NOP();
- g_motor_data.board_temp = get_temp(g_adc_val[1]);
- __NOP();__NOP();__NOP();
- atk_debug_send_temp(0,get_temp(g_adc_val[1]));
- __NOP();__NOP();__NOP();
- //g_motor_data.current = (g_adc_val[2]*ADC2CURT)*0.001;
- atk_debug_send_current(g_motor_data.current*0.001,0,0);
- __NOP();__NOP();__NOP();
- atk_debug_send_speed(g_motor_data.speed);
- __NOP();__NOP();__NOP();
- // printf("\r\n******************************\r\n");
- // printf("KEY0:增加比较值,KEY1:减小比较值,KEY2:停止电机\r\n\r\n");
- // printf("Valtage:%.2fV \r\n", g_motor_data.volatage); /* 打印电压值 */
- // printf("Temp:%.2fC \r\n", g_motor_data.board_temp ); /* 打印温度值 */
- // printf("Current:%.2fmA \r\n", g_motor_data.current); /* 打印电流值 */
- // printf("电机速度:%.1f RPM\r\n\r\n", g_motor_data.speed);
- // printf("\r\n******************************\r\n");
- }
- else if(g_time % SMAPLSE_PID_SPEED == 0) /* 电机速度 50ms进行一次pid计算 */
- {
- if(g_run_flag)
- {
-
- /* PID计算,输出比较值(占空比) */
- motor_pwm_temp = increment_pid_ctrl (&g_current_pid,g_motor_data.current);
- g_motor_data.motor_pwm = (int32_t)((g_motor_data.motor_pwm * 0.5) + (motor_pwm_temp * 0.5));
- if(g_motor_data.motor_pwm >= 8200)
- {
- g_motor_data.motor_pwm = 8200;
- }
- else if (g_motor_data.motor_pwm <= 0)
- {
- g_motor_data.motor_pwm = 0;
- }
-
- Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1); /* 设置电机转速 */
- }
- atk_debug_send_wave_data( 1 ,g_motor_data.current); /* 选择通道1发送实际电流(波形显示)*/
- atk_debug_send_wave_data( 2 ,g_current_pid.SetPoint); /* 选择通道2,发送目标电流(波形显示)*/
- atk_debug_send_wave_data( 3 ,g_motor_data.motor_pwm * 100 / 8400); /* 选择通道3,发送占空比(波形显示)*/
- }
- g_time ++;
-
- }
- void get_EncodeValue(uint8_t ms)
- {
- int encode_now = gtim_get_encode();
- speed_computer(encode_now, ms);
- }
- PID_TypeDef g_speed_pid; /* 速度环PID参数结构体 */
- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] pid初始化
- * @param 无
- * @retval 无
- */
- void pid_init(void)
- {
-
- memset(&g_motor_data,0,sizeof(g_motor_data));
- memset(&g_current_pid,0,sizeof(g_current_pid));
-
- g_current_pid.SetPoint = 0; /* 设定目标值 */
- g_current_pid.ActualValue = 0.0; /* 期望输出值 */
- g_current_pid.SumError = 0.0; /* 积分值 */
- g_current_pid.Error = 0.0; /* Error[1] */
- g_current_pid.LastError = 0.0; /* Error[-1] */
- g_current_pid.PrevError = 0.0; /* Error[-2] */
- g_current_pid.Proportion = KP; /* 比例常数 Proportional Const */
- g_current_pid.Integral = KI; /* 积分常数 Integral Const */
- g_current_pid.Derivative = KD; /* 微分常数 Derivative Const */
- }
- void DCMotorsample_Init(void)
- {
- pid_init();
- ADC1CbReg(get_Motor_value);
- }
速度环:
- #include "main.h"
- #include "math.h"
- /************************************* 第二部分 电压电流温度采集 **********************************************/
- uint16_t g_adc_val[ADC_CH_NUM]; /*ADC平均值存放数组*/
- PID_TypeDef g_speed_pid; /*速度环PID参数结构体*/
- /*
- Rt = Rp *exp(B*(1/T1-1/T2))
- Rt 是热敏电阻在T1温度下的阻值;
- Rp是热敏电阻在T2常温下的标称阻值;
- exp是e的n次方,e是自然常数,就是自然对数的底数,近似等于 2.7182818;
- B值是热敏电阻的重要参数,教程中用到的热敏电阻B值为3380;
- 这里T1和T2指的是开尔文温度,T2是常温25℃,即(273.15+25)K
- T1就是所求的温度
- */
- const float Rp = 10000.0f; /* 10K */
- const float T2 = (273.15f + 25.0f); /* T2 */
- const float Bx = 3380.0f; /* B */
- const float Ka = 273.15f;
- Motor_TypeDef g_motor_data; /*电机参数变量*/
- ENCODE_TypeDef g_encode; /*编码器参数变量*/
- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] 计算温度值
- * @param para: 温度采集对应ADC通道的值(已滤波)
- * [url=home.php?mod=space&uid=536309]@NOTE[/url] 计算温度分为两步:
- 1.根据ADC采集到的值计算当前对应的Rt
- 2.根据Rt计算对应的温度值
- * @retval 温度值
- */
- float get_temp(uint16_t para)
- {
- float Rt;
- float temp;
-
- /*
- 第一步:
- Rt = 3.3 * 4700 / VTEMP - 4700 ,其中VTEMP就是温度检测通道采集回来的电压值,VTEMP = ADC值* 3.3/4096
- 由此我们可以计算出当前Rt的值:Rt = 3.3f * 4700.0f / (para * 3.3f / 4096.0f ) - 4700.0f;
- */
-
- Rt = 3.3f * 4700.0f / (para * 3.3f / 4096.0f ) - 4700.0f; /* 根据当前ADC值计算出Rt的值 */
- /*
- 第二步:
- 根据当前Rt的值来计算对应温度值:Rt = Rp *exp(B*(1/T1-1/T2))
- */
-
- temp = Rt / Rp; /* 解出exp(B*(1/T1-1/T2)) ,即temp = exp(B*(1/T1-1/T2)) */
- temp = log(temp); /* 解出B*(1/T1-1/T2) ,即temp = B*(1/T1-1/T2) */
- temp /= Bx; /* 解出1/T1-1/T2 ,即temp = 1/T1-1/T2 */
- temp += (1.0f / T2); /* 解出1/T1 ,即temp = 1/T1 */
- temp = 1.0f / (temp); /* 解出T1 ,即temp = T1 */
- temp -= Ka; /* 计算T1对应的摄氏度 */
- return temp; /* 返回温度值 */
- }
- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] 计算ADC的平均值(滤波)
- * @param * p :存放ADC值的指针地址
- * [url=home.php?mod=space&uid=536309]@NOTE[/url] 此函数对电压、温度、电流对应的ADC值进行滤波,
- * p[0]-p[2]对应的分别是电压、温度和电流
- * @retval 无
- */
- void calc_adc_val(uint16_t * adcdata)
- {
- uint32_t temp[3] = {0,0,0};
- uint16_t i;
- for(i=0;i<ADC_COLL;i++) /* 循环ADC_COLL次取值,累加 */
- {
- temp[0] += adcdata[0+i*ADC_CH_NUM];
- temp[1] += adcdata[1+i*ADC_CH_NUM];
- temp[2] += adcdata[2+i*ADC_CH_NUM];
- }
- temp[0] /= ADC_COLL; /* 取平均值 */
- temp[1] /= ADC_COLL;
- temp[2] /= ADC_COLL;
-
- g_adc_val[0] = temp[0]; /* 存入电压ADC通道平均值 */
- g_adc_val[1] = temp[1]; /* 存入温度ADC通道平均值 */
- g_adc_val[2] = temp[2]; /* 存入电流ADC通道平均值 */
- }
- void get_Motor_value(uint16_t * adcdata)
- {
- calc_adc_val(adcdata);
-
- }
- /************************************* 第三部分 编码器测速 ****************************************************/
- void speed_computer(int32_t encode_now, uint8_t ms)
- {
- uint8_t i = 0, j = 0;
- float temp = 0.0;
- static uint8_t sp_count = 0, k = 0;
- static float speed_arr[10] = {0.0}; /* 存储速度进行滤波运算 */
- if (sp_count == ms) /* 计算一次速度 */
- {
- /* 计算电机转速
- 第一步 :计算ms毫秒内计数变化量
- 第二步 ;计算1min内计数变化量:g_encode.speed * ((1000 / ms) * 60 ,
- 第三步 :除以编码器旋转一圈的计数次数(倍频倍数 * 编码器分辨率)
- 第四步 :除以减速比即可得出电机转速
- */
- g_encode.encode_now = encode_now; /* 取出编码器当前计数值 */
- g_encode.speed = (g_encode.encode_now - g_encode.encode_old); /* 计算编码器计数值的变化量 */
-
- speed_arr[k++] = (float)(g_encode.speed * ((1000 / ms) * 60.0) / REDUCTION_RATIO / ROTO_RATIO ); /* 保存电机转速 */
-
- g_encode.encode_old = g_encode.encode_now; /* 保存当前编码器的值 */
- /* 累计10次速度值,后续进行滤波*/
- if (k == 10)
- {
- for (i = 10; i >= 1; i--) /* 冒泡排序*/
- {
- for (j = 0; j < (i - 1); j++)
- {
- if (speed_arr[j] > speed_arr[j + 1]) /* 数值比较 */
- {
- temp = speed_arr[j]; /* 数值换位 */
- speed_arr[j] = speed_arr[j + 1];
- speed_arr[j + 1] = temp;
- }
- }
- }
-
- temp = 0.0;
-
- for (i = 2; i < 8; i++) /* 去除两边高低数据 */
- {
- temp += speed_arr[i]; /* 将中间数值累加 */
- }
-
- temp = (float)(temp / 6); /*求速度平均值*/
-
- /* 一阶低通滤波
- * 公式为:Y(n)= qX(n) + (1-q)Y(n-1)
- * 其中X(n)为本次采样值;Y(n-1)为上次滤波输出值;Y(n)为本次滤波输出值,q为滤波系数
- * q值越小则上一次输出对本次输出影响越大,整体曲线越平稳,但是对于速度变化的响应也会越慢
- */
- g_motor_data.speed = (float)( ((float)0.48 * temp) + (g_motor_data.speed * (float)0.52) );
- k = 0;
- }
- sp_count = 0;
- }
- sp_count ++;
- }
- uint8_t g_run_flag = 0;
- int32_t motor_pwm = 0;
- void DCMotor_App(void)
- {
- static uint8_t key=0;
- key=key_scan(0);
- if(key == KEY0_PRES)
- {
- TurnTogLed(LED1);
- g_speed_pid.SetPoint +=30;
- g_run_flag = 1;
- if (g_speed_pid.SetPoint == 0)
- {
- DC_Motor_Stop(MOTOR_1); /* 停止则立刻响应 */
- g_motor_data.motor_pwm = 0;
- Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1); /* 设置电机转速 */
- }
- else
- {
- DC_Motor_Start(MOTOR_1);
- if(g_speed_pid.SetPoint >= 300)
- {
- g_speed_pid.SetPoint =300;
- }
- atk_debug_send_motorstate(RUN_STATE); /* 上传电机状态(运行) */
- DC_Motor_Speed(g_speed_pid.SetPoint,MOTOR_1); /* 设置电机转速 */
- }
- }
- else if(key == KEY1_PRES) {
- TurnTogLed(LED1);
- g_speed_pid.SetPoint -= 30;
- g_run_flag = 1;
- if (g_speed_pid.SetPoint == 0)
- {
- DC_Motor_Stop(MOTOR_1); /* 停止则立刻响应 */
- g_motor_data.motor_pwm = 0;
- DC_Motor_Speed(g_motor_data.motor_pwm,MOTOR_1); /* 设置电机转速 */
- }
- else
- {
- DC_Motor_Start(MOTOR_1);
- if(g_speed_pid.SetPoint <= -300)
- {
- g_speed_pid.SetPoint =-300;
- }
- DC_Motor_Speed(g_speed_pid.SetPoint,MOTOR_1); /* 设置电机转速 */
- atk_debug_send_motorstate(RUN_STATE); /* 上传电机状态(运行) */
- }
- }
- else if(key == KEY2_PRES)
- {
- DC_Motor_Stop(MOTOR_1);
- g_run_flag = 0; /* 标记电机停止 */
- g_motor_data.motor_pwm = 0;
- Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1); /* 设置电机转向、速度 */
- g_speed_pid.SetPoint = 0;
- pid_init();
- atk_debug_send_motorstate(BREAKED_STATE); /* 上传电机状态(刹车) */
- atk_debug_send_initdata(TYPE_PID1, (float *)(&g_speed_pid.SetPoint), KP, KI, KD); /* 同步数据到上位机 */
- }
- }
- void DCMotor_Value(void)
- {
- static uint16_t init_adc_val = 0;
- static uint16_t g_time =0;
- static uint8_t num = 0;
- if(num < 2)
- {
- num ++;
- atk_debug_send_motorcode(DC_MOTOR); /* 上传电机类型(直流有刷电机) */
- atk_debug_send_motorstate(IDLE_STATE); /* 上传电机状态(空闲) */
- init_adc_val = g_adc_val[2];
- init_adc_val += g_adc_val[2]; /* 现在的值和上一次存储的值相加 */
- init_adc_val /= 2;
- }else
- {
-
-
-
- /* 获取编码器值,用于计算速度 */
- get_EncodeValue(5); /* 中位平均值滤除编码器抖动数据,5ms计算一次速度*/
-
- if(g_time % 1000 ==0)
- {
-
- __NOP();__NOP();__NOP();
- g_motor_data.board_temp = get_temp(g_adc_val[1]);
-
- //
- printf("\r\n******************************\r\n");
- printf("KEY0:增加比较值,KEY1:减小比较值,KEY2:停止电机\r\n\r\n");
- printf("Valtage:%.2fV \r\n", g_motor_data.volatage); /* 打印电压值 */
- printf("Temp:%.2fC \r\n", g_motor_data.board_temp ); /* 打印温度值 */
- printf("Current:%.2fmA \r\n", g_motor_data.current); /* 打印电流值 */
- printf("电机速度:%.1f RPM\r\n\r\n", g_motor_data.speed);
- printf("\r\n******************************\r\n");
- }
- else if(g_time %300 == 0)
- {
- atk_debug_send_temp(0,get_temp(g_adc_val[1]));
- }
- else if(g_time %200 == 0)
- {
- g_motor_data.volatage = g_adc_val[0]*ADC2VBUS;
- atk_debug_send_valtage(g_motor_data.volatage );
- }
- else if(g_time % SMAPLSE_PID_SPEED == 0) /* 电机速度 50ms进行一次pid计算 */
- {
- atk_debug_send_speed(g_motor_data.speed);
- if(g_run_flag)
- {
-
- /* PID计算,输出比较值(占空比) */
- g_motor_data.motor_pwm = increment_pid_ctrl (&g_speed_pid,g_motor_data.speed);
-
- if(g_motor_data.motor_pwm >= 8200)
- {
- g_motor_data.motor_pwm = 8200;
- }
- else if (g_motor_data.motor_pwm <= -8200)
- {
- g_motor_data.motor_pwm = -8200;
- }
-
- Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1); /* 设置电机转速 */
- }
- atk_debug_send_wave_data( 1 ,g_motor_data.speed); /* 选择通道1,发送实际速度(波形显示)*/
- atk_debug_send_wave_data( 2 ,g_speed_pid.SetPoint); /* 选择通道2,发送目标速度(波形显示)*/
- atk_debug_send_wave_data( 3 ,g_motor_data.motor_pwm * 100 / 8400); /* 选择通道3,发送占空比(波形显示)*/
- }
- else if(g_time % 20 == 0)
- {
- g_motor_data.current = (abs(g_adc_val[2]-init_adc_val)*ADC2CURT)*0.001;
- atk_debug_send_current(g_motor_data.current,0,0);
- }
- g_time ++;
- }
- }
- void get_EncodeValue(uint8_t ms)
- {
- int encode_now = gtim_get_encode();
- speed_computer(encode_now, ms);
- }
- PID_TypeDef g_speed_pid; /* 速度环PID参数结构体 */
- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] pid初始化
- * @param 无
- * @retval 无
- */
- void pid_init(void)
- {
-
- memset(&g_motor_data,0,sizeof(g_motor_data));
- memset(&g_speed_pid,0,sizeof(g_speed_pid));
-
- /* 初始化速度环PID参数 */
- g_speed_pid.SetPoint = 0; /* 设定目标值 */
- g_speed_pid.ActualValue = 0.0; /* 期望输出值 */
- g_speed_pid.SumError = 0.0; /* 积分值 */
- g_speed_pid.Error = 0.0; /* Error[1] */
- g_speed_pid.LastError = 0.0; /* Error[-1] */
- g_speed_pid.PrevError = 0.0; /* Error[-2] */
- g_speed_pid.Proportion = KP; /* 比例常数 Proportional Const */
- g_speed_pid.Integral = KI; /* 积分常数 Integral Const */
- g_speed_pid.Derivative = KD; /* 微分常数 Derivative Const */
-
- atk_debug_send_wave_data( 1 ,g_motor_data.speed); /* 选择通道1,发送实际速度(波形显示)*/
- atk_debug_send_wave_data( 2 ,g_speed_pid.SetPoint); /* 选择通道2,发送目标速度(波形显示)*/
- atk_debug_send_wave_data( 3 ,g_motor_data.motor_pwm * 100 / 8400); /* 选择通道3,发送占空比(波形显示)*/
- }
- void DCMotorsample_Init(void)
- {
- pid_init();
- ADC1CbReg(get_Motor_value);
- }
位置环:- #include "main.h"
- #include "math.h"
- /************************************* 第二部分 电压电流温度采集 **********************************************/
- uint16_t g_adc_val[ADC_CH_NUM]; /*ADC平均值存放数组*/
- PID_TypeDef g_location_pid; /*位置环PID参数结构体*/
- /*
- Rt = Rp *exp(B*(1/T1-1/T2))
- Rt 是热敏电阻在T1温度下的阻值;
- Rp是热敏电阻在T2常温下的标称阻值;
- exp是e的n次方,e是自然常数,就是自然对数的底数,近似等于 2.7182818;
- B值是热敏电阻的重要参数,教程中用到的热敏电阻B值为3380;
- 这里T1和T2指的是开尔文温度,T2是常温25℃,即(273.15+25)K
- T1就是所求的温度
- */
- const float Rp = 10000.0f; /* 10K */
- const float T2 = (273.15f + 25.0f); /* T2 */
- const float Bx = 3380.0f; /* B */
- const float Ka = 273.15f;
- Motor_TypeDef g_motor_data; /*电机参数变量*/
- ENCODE_TypeDef g_encode; /*编码器参数变量*/
- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] 计算温度值
- * @param para: 温度采集对应ADC通道的值(已滤波)
- * [url=home.php?mod=space&uid=536309]@NOTE[/url] 计算温度分为两步:
- 1.根据ADC采集到的值计算当前对应的Rt
- 2.根据Rt计算对应的温度值
- * @retval 温度值
- */
- float get_temp(uint16_t para)
- {
- float Rt;
- float temp;
-
- /*
- 第一步:
- Rt = 3.3 * 4700 / VTEMP - 4700 ,其中VTEMP就是温度检测通道采集回来的电压值,VTEMP = ADC值* 3.3/4096
- 由此我们可以计算出当前Rt的值:Rt = 3.3f * 4700.0f / (para * 3.3f / 4096.0f ) - 4700.0f;
- */
-
- Rt = 3.3f * 4700.0f / (para * 3.3f / 4096.0f ) - 4700.0f; /* 根据当前ADC值计算出Rt的值 */
- /*
- 第二步:
- 根据当前Rt的值来计算对应温度值:Rt = Rp *exp(B*(1/T1-1/T2))
- */
-
- temp = Rt / Rp; /* 解出exp(B*(1/T1-1/T2)) ,即temp = exp(B*(1/T1-1/T2)) */
- temp = log(temp); /* 解出B*(1/T1-1/T2) ,即temp = B*(1/T1-1/T2) */
- temp /= Bx; /* 解出1/T1-1/T2 ,即temp = 1/T1-1/T2 */
- temp += (1.0f / T2); /* 解出1/T1 ,即temp = 1/T1 */
- temp = 1.0f / (temp); /* 解出T1 ,即temp = T1 */
- temp -= Ka; /* 计算T1对应的摄氏度 */
- return temp; /* 返回温度值 */
- }
- /**
- * @brief 计算ADC的平均值(滤波)
- * @param * p :存放ADC值的指针地址
- * [url=home.php?mod=space&uid=536309]@NOTE[/url] 此函数对电压、温度、电流对应的ADC值进行滤波,
- * p[0]-p[2]对应的分别是电压、温度和电流
- * @retval 无
- */
- void calc_adc_val(uint16_t * adcdata)
- {
- uint32_t temp[3] = {0,0,0};
- uint16_t i;
- for(i=0;i<ADC_COLL;i++) /* 循环ADC_COLL次取值,累加 */
- {
- temp[0] += adcdata[0+i*ADC_CH_NUM];
- temp[1] += adcdata[1+i*ADC_CH_NUM];
- temp[2] += adcdata[2+i*ADC_CH_NUM];
- }
- temp[0] /= ADC_COLL; /* 取平均值 */
- temp[1] /= ADC_COLL;
- temp[2] /= ADC_COLL;
-
- g_adc_val[0] = temp[0]; /* 存入电压ADC通道平均值 */
- g_adc_val[1] = temp[1]; /* 存入温度ADC通道平均值 */
- g_adc_val[2] = temp[2]; /* 存入电流ADC通道平均值 */
- }
- void get_Motor_value(uint16_t * adcdata)
- {
- calc_adc_val(adcdata);
-
- }
- /************************************* 第三部分 编码器测速 ****************************************************/
- void speed_computer(int32_t encode_now, uint8_t ms)
- {
- uint8_t i = 0, j = 0;
- float temp = 0.0;
- static uint8_t sp_count = 0, k = 0;
- static float speed_arr[10] = {0.0}; /* 存储速度进行滤波运算 */
- if (sp_count == ms) /* 计算一次速度 */
- {
- /* 计算电机转速
- 第一步 :计算ms毫秒内计数变化量
- 第二步 ;计算1min内计数变化量:g_encode.speed * ((1000 / ms) * 60 ,
- 第三步 :除以编码器旋转一圈的计数次数(倍频倍数 * 编码器分辨率)
- 第四步 :除以减速比即可得出电机转速
- */
- g_encode.encode_now = encode_now; /* 取出编码器当前计数值 */
- g_encode.speed = (g_encode.encode_now - g_encode.encode_old); /* 计算编码器计数值的变化量 */
-
- speed_arr[k++] = (float)(g_encode.speed * ((1000 / ms) * 60.0) / REDUCTION_RATIO / ROTO_RATIO ); /* 保存电机转速 */
-
- g_encode.encode_old = g_encode.encode_now; /* 保存当前编码器的值 */
- /* 累计10次速度值,后续进行滤波*/
- if (k == 10)
- {
- for (i = 10; i >= 1; i--) /* 冒泡排序*/
- {
- for (j = 0; j < (i - 1); j++)
- {
- if (speed_arr[j] > speed_arr[j + 1]) /* 数值比较 */
- {
- temp = speed_arr[j]; /* 数值换位 */
- speed_arr[j] = speed_arr[j + 1];
- speed_arr[j + 1] = temp;
- }
- }
- }
-
- temp = 0.0;
-
- for (i = 2; i < 8; i++) /* 去除两边高低数据 */
- {
- temp += speed_arr[i]; /* 将中间数值累加 */
- }
-
- temp = (float)(temp / 6); /*求速度平均值*/
-
- /* 一阶低通滤波
- * 公式为:Y(n)= qX(n) + (1-q)Y(n-1)
- * 其中X(n)为本次采样值;Y(n-1)为上次滤波输出值;Y(n)为本次滤波输出值,q为滤波系数
- * q值越小则上一次输出对本次输出影响越大,整体曲线越平稳,但是对于速度变化的响应也会越慢
- */
- g_motor_data.speed = (float)( ((float)0.48 * temp) + (g_motor_data.speed * (float)0.52) );
- k = 0;
- }
- sp_count = 0;
- }
- sp_count ++;
- }
- uint8_t g_run_flag = 0;
- int32_t motor_pwm = 0;
- void DCMotor_App(void)
- {
- static uint8_t key=0;
- key=key_scan(0);
- if(key == KEY0_PRES)
- {
- TurnTogLed(LED1);
- g_location_pid.SetPoint +=1320; /* 正转一圈,电机旋转圈数 = 计数值变化量 / 44 / 30 */
- g_run_flag = 1;
- if (g_location_pid.SetPoint == 0)
- {
- DC_Motor_Stop(MOTOR_1); /* 停止则立刻响应 */
- g_motor_data.motor_pwm = 0;
- Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1); /* 设置电机转速 */
- }
- else
- {
- DC_Motor_Start(MOTOR_1);
- if(g_location_pid.SetPoint >= 6600)
- {
- g_location_pid.SetPoint =6600;
- }
- atk_debug_send_motorstate(RUN_STATE); /* 上传电机状态(运行) */
- DC_Motor_Speed(g_location_pid.SetPoint,MOTOR_1); /* 设置电机转速 */
- }
- }
- else if(key == KEY1_PRES) {
- TurnTogLed(LED1);
- g_location_pid.SetPoint -= 1320; /* 正转一圈,电机旋转圈数 = 计数值变化量 / 44 / 30 */
- g_run_flag = 1;
- if (g_location_pid.SetPoint == 0)
- {
- DC_Motor_Stop(MOTOR_1); /* 停止则立刻响应 */
- g_motor_data.motor_pwm = 0;
- DC_Motor_Speed(g_motor_data.motor_pwm,MOTOR_1); /* 设置电机转速 */
- }
- else
- {
- DC_Motor_Start(MOTOR_1);
- if(g_location_pid.SetPoint <= -6600)
- {
- g_location_pid.SetPoint =-6600;
- }
- DC_Motor_Speed(g_location_pid.SetPoint,MOTOR_1); /* 设置电机转速 */
- atk_debug_send_motorstate(RUN_STATE); /* 上传电机状态(运行) */
- }
- }
- else if(key == KEY2_PRES)
- {
- DC_Motor_Stop(MOTOR_1);
- g_run_flag = 0; /* 标记电机停止 */
- g_motor_data.motor_pwm = 0;
- Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1); /* 设置电机转向、速度 */
- g_location_pid.SetPoint = 0;
- pid_init();
- atk_debug_send_motorstate(BREAKED_STATE); /* 上传电机状态(刹车) */
- atk_debug_send_initdata(TYPE_PID1, (float *)(&g_location_pid.SetPoint), KP, KI, KD); /* 同步数据到上位机 */
- }
- }
- void DCMotor_Value(void)
- {
- int32_t motor_pwm_temp = 0;
- static uint16_t init_adc_val = 0;
- static uint16_t g_time =0;
- static uint8_t num = 0;
- if(num < 2)
- {
- num ++;
- atk_debug_send_motorcode(DC_MOTOR); /* 上传电机类型(直流有刷电机) */
- atk_debug_send_motorstate(IDLE_STATE); /* 上传电机状态(空闲) */
- init_adc_val = g_adc_val[2];
- init_adc_val += g_adc_val[2]; /* 现在的值和上一次存储的值相加 */
- init_adc_val /= 2;
- }else
- {
-
-
- /* 获取编码器值,用于计算速度 */
- get_EncodeValue(5); /* 中位平均值滤除编码器抖动数据,5ms计算一次速度*/
-
- if(g_time % 1000 ==0)
- {
-
- g_motor_data.volatage = g_adc_val[0]*ADC2VBUS;
- atk_debug_send_valtage(g_motor_data.volatage );
- __NOP();__NOP();__NOP();
- g_motor_data.board_temp = get_temp(g_adc_val[1]);
- atk_debug_send_temp(0,g_motor_data.board_temp);
- __NOP();__NOP();__NOP();
-
- g_motor_data.current = (abs(g_adc_val[2]-init_adc_val)*ADC2CURT)*0.001;
- atk_debug_send_current(g_motor_data.current,0,0);
- __NOP();__NOP();__NOP();
-
- // printf("\r\n******************************\r\n");
- // printf("KEY0:增加比较值,KEY1:减小比较值,KEY2:停止电机\r\n\r\n");
- // printf("Valtage:%.2fV \r\n", g_motor_data.volatage); /* 打印电压值 */
- // printf("Temp:%.2fC \r\n", g_motor_data.board_temp ); /* 打印温度值 */
- // printf("Current:%.2fmA \r\n", g_motor_data.current); /* 打印电流值 */
- // printf("电机速度:%.1f RPM\r\n\r\n", g_motor_data.speed);
- // printf("\r\n******************************\r\n");
- }
- else if(g_time % SMAPLSE_PID_SPEED == 0) /* 电机速度 50ms进行一次pid计算 */
- {
- if(g_run_flag == 1)
- {
- /* PID计算,输出比较值(占空比),再进行一阶低通滤波 */
- motor_pwm_temp = increment_pid_ctrl(&g_location_pid,g_motor_data.location);
- g_motor_data.motor_pwm = (int32_t)((g_motor_data.motor_pwm * 0.5) + (motor_pwm_temp * 0.5));
- if (g_motor_data.motor_pwm >= 3000) /* 限制占空比 */
- {
- g_motor_data.motor_pwm = 3000;
- }
- else if (g_motor_data.motor_pwm <= -3000)
- {
- g_motor_data.motor_pwm = -3000;
- }
- atk_debug_send_wave_data( 1 ,g_motor_data.location); /* 选择通道1,发送实际位置(波形显示)*/
- atk_debug_send_wave_data( 2 ,g_location_pid.SetPoint); /* 选择通道2,发送目标位置(波形显示)*/
-
- Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1);
- }
- }
- g_time ++;
- }
- }
- void get_EncodeValue(uint8_t ms)
- {
- int encode_now = gtim_get_encode();
-
- g_motor_data.location = encode_now; /* 获取当前计数总值,用于位置闭环控制 */
- speed_computer(encode_now, ms);
- }
- /**
- * @brief pid初始化
- * @param 无
- * @retval 无
- */
- void pid_init(void)
- {
-
- memset(&g_motor_data,0,sizeof(g_motor_data));
- memset(&g_location_pid,0,sizeof(g_location_pid));
-
- g_location_pid.SetPoint = 0.0; /* 设定目标值 */
- g_location_pid.ActualValue = 0.0; /* 期望输出值 */
- g_location_pid.SumError = 0.0; /* 积分值 */
- g_location_pid.Error = 0.0; /* Error[1] */
- g_location_pid.LastError = 0.0; /* Error[-1] */
- g_location_pid.PrevError = 0.0; /* Error[-2] */
- g_location_pid.Proportion = KP; /* 比例常数 Proportional Const */
- g_location_pid.Integral = KI; /* 积分常数 Integral Const */
- g_location_pid.Derivative = KD; /* 微分常数 Derivative Const */
-
- atk_debug_send_wave_data( 1 ,g_motor_data.speed); /* 选择通道1,发送实际速度(波形显示)*/
- atk_debug_send_wave_data( 2 ,g_location_pid.SetPoint); /* 选择通道2,发送目标速度(波形显示)*/
- atk_debug_send_wave_data( 3 ,g_motor_data.motor_pwm * 100 / 8400); /* 选择通道3,发送占空比(波形显示)*/
- }
- void DCMotorsample_Init(void)
- {
- pid_init();
- ADC1CbReg(get_Motor_value);
- }