在过程贴中,成功驱动OLED、INA219模块,能够实时的显示电机的电压、电流、功率等电气参数,在此基础上,添加电机的自锁、打嗝功能。自锁模式能够在电机过流后自动关闭电机;打嗝模式则是在电机产生过流后,关闭电机一段时间,再重新启动电机。
// 过流阈值,单位mA volatile float OVERCURRENT_THRESHOLD = 90.0f; // 控制模式,0:自锁模式,1:打嗝模式 volatile uint8_t control_mode = 0; // 过流标志 volatile float overcurrent_flag = 0;
设定volatile修饰变量,防止编译器优化变量,每次访问时都从内存读取其最新值。
// 中位值平均滤波电流 float Med_Avg_Filter_Current(void) { unsigned int count, i, j, temp; float value_buff[N]; // 存储电流采样值 float current_sum = 0; // 采样N次电流 for (count = 0; count < N; count++) { value_buff[count] = INA219_ReadCurrent(); // 读取电流 delay_ms(2); } // 冒泡排序升序排列 for (j = 0; j < N - 1; j++) { for (i = 0; i < N - j - 1; i++) { if (value_buff[i] > value_buff[i + 1]) { temp = value_buff[i]; value_buff[i] = value_buff[i + 1]; value_buff[i + 1] = temp; } } } // 排除最大和最小值,求中间项和 for (count = 1; count < N - 1; count++) // 过滤掉最大值和最小值 { current_sum += value_buff[count]; } // 返回滤波后的电流值 return (current_sum / (N - 2)); }
采用中位值平均滤波电流,平滑电流显示,避免电流读数跳动太大。
编写一个过流检测函数,并将这个函数放到定时器中断函数里面,每100ms执行一次。继电器的PIN脚连接到LD2,这样可以通过LED直观的展示继电器通断状态。
/** * @brief 过流检测 * */ void Overcurrent_Protection(void) { // 读取当前电流 float current = Med_Avg_Filter_Current(); // 判断是否超过阈值 if (current > OVERCURRENT_THRESHOLD) { if (!overcurrent_flag) // 如果当前没有触发过流 { overcurrent_flag = 1; // 设置过流标志 LD2_OFF(); // 断开电机 } } else { if (overcurrent_flag) // 如果电流回落并且处于过流状态 { if (control_mode == 0) // 自锁模式 { LD2_OFF(); } else if (control_mode == 1) // 打嗝模式 { overcurrent_flag = 0; } } } }
OLED设置了两个页面,采用中断按键的方式,大幅提高按键的灵敏度。
void EXTI15_10_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line13) != RESET) // 确保是否产生了EXTI Line中断 { // 按键按下,切换页面 if (current_page == 0) { OLED_Clear(); current_page = 1; // 更新为设置页 } else { OLED_Clear(); current_page = 0; // 更新为首页 } delay_ms(20); EXTI_ClearITPendingBit(EXTI_Line13); // 清除中断标志位 } }
串口使用的USART2,但是在串口软件接收到的是乱码,大佬们可以看一下程序代码,指出其中的问题。
演示视频:
https://www.bilibili.com/video/BV16zN4zuEJ2/
程序放置于此,请结合上述使用: