ADC相关
如何读取ADC电压的上升沿和下降沿
如图:
思路:
定义两个变量volt_prev 和 volt_now,一个读取当前电压值,另一个保存上一次的电压值并设定一个参考电压volt_refer。
( volt_prev > volt_refer ) && ( volt_now < volt_refer ) 电压下降沿
( volt_prev < volt_refer ) && ( volt_now > volt_refer ) 电压上升沿
代码部分(选自11届第1套)
1.
/* ADC */
u16 adc_val;
float volt_r37_prev;
void ADC_Process()
{
HAL_ADC_Start(&hadc2);
adc_val = HAL_ADC_GetValue(&hadc2);
volt_r37_prev = volt_r37;//保存上一个时刻的电压
volt_r37 = adc_val/4095.0f*3.30f;//获取当前电压值
}
2.
if( (volt_r37_prev <= volt_min_val) && volt_r37 > volt_min_val)//判断为电压上升沿
{
}
if(volt_r37_prev >= volt_min_val && volt_r37 < volt_max_val)//判断为电压下降沿
{
}
LCD显示的高亮选中
如图,我们要在界面实现选中高亮。
程序思路
定义一个高亮索引,select_index。通过按键增减select_index的值,控制高亮的行。
LCD_SetBackColor(Green);//高亮使用的颜色
LCD_DisplayStringLine(Line4,display_buf);
LCD_SetBackColor(White);//最终的背景色
代码部分
sprintf((char*)display_buf," Seting ");
LCD_DisplayStringLine(Line1,display_buf);
//选中上限电压 高亮显示
sprintf((char*)display_buf," Max Volt:%.1fV ",max_volt);
if(select_index == 1)
{
LCD_SetBackColor(Green);
LCD_DisplayStringLine(Line2,display_buf);
LCD_SetBackColor(White);
}
else//正常显示
{
LCD_DisplayStringLine(Line2,display_buf);
}
//选中下限电压 高亮显示
sprintf((char*)display_buf," Min Volt:%.1fV ",min_volt);
if(select_index == 2)
{
LCD_SetBackColor(Green);
LCD_DisplayStringLine(Line4,display_buf);
LCD_SetBackColor(White);
}
else//正常显示
{
LCD_DisplayStringLine(Line4,display_buf);
}
设计编程细节
修改参数后的生效时间
- 修改后的参数是在从参数设置界面切换到数据显示界面后生效
- 修改后的参数即时生效(比上面的代码要复杂很多)
参数电压的显示
参数的电压变量推荐用u8类型表示,显示的时候再进行类型转换。这样的设置会方便后续的编程。如果有参数进行比较,float的精度过多容易影响判断。
如果电压参数要保存在EEPROM中,那么更加推荐电压参数设置为u8,因为EEPROM函数默认保存u8类型的数据。
LED进阶
LED闪烁指定时间闪烁
(1)让LED以0.5S(500ms)为间隔闪烁
程序思路:让LED_Process()每100ms执行一次。500ms亮,100ms灭
//LED
u8 led_ctrl = 0x00;
u32 ledTick = 0;
u16 cnt_led = 0;
void LED_Process()
{
if(uwTick - ledTick < 100) return;//每100ms执行一次led功能
ledTick = uwTick;
/* //亮灭时间不同时的解决办法:
//以下程序举例为亮500ms,灭100ms
if(volt_r37 > 1.0f)
{
cnt_led = (cnt_led + 1)%6;//cnt_led范围为0-5
if(cnt_led <= 4)//500ms亮
led_ctrl |= 0x02;
else if(cnt_led <= 5)//100ms灭
led_ctrl &= ~0x02;
}
else
led_ctrl &= ~0x02;
*/
LED_Control(led_ctrl);
}
LED指定时间后熄灭
例:confirm_5s_flag = 1后,LED1亮5S后熄灭。
u16 led_cnt1 = 0;
//1ms中断函数
void SysTick_Handler(void)
{
HAL_IncTick();
if(confirm_5s_flag == 1)
{
led_cnt1++;
if(led_cnt1 == 5000)
{
led_cnt1 = 0;
confirm_5s_flag = 0;
}
}
}
* LED */
u8 led_ctrl = 0x00;
void LED_Process()
{
if(confirm_5s_flag == 1)
led_ctrl |= 0x01;
else
led_ctrl &= ~0x01;
LED_Control(led_ctrl);
}
按键按下后指定时间后生效
例:按下B2后,5S后切换PWM模式,即pwm_mode+1;
基本思路
定义计时变量b2Tick,计时标志位pwm_mode_flag。按下B2,b2Tick = uwTick,pwm_mode_flag =1 ;当(uwTick - b2Tick)>= 5000 && pwm_mode_flag == 1 时,切换模式,同时计时标志位pwm_mode_flag清零。
代码部分
/* 按键 */
u32 keyTick;
_Bool pwm_mode_flag;
u32 b2Tick;
void KEY_Process()
{
if(uwTick - keyTick < 20) return;
keyTick = uwTick;
Key_Read();
if(uwTick - b2Tick >= 5000 && pwm_mode_flag == 1)//pwm_mode_flag=1后,5000ms后执行一次
{
pwm_change_num++;
pwm_mode = (pwm_mode+1)%2;
pwm_mode_flag = 0;
}
}
if(Trg & 0x02)//B2 选择按键
{
switch(display_mode)
{
case DATA:
{
if(pwm_mode_flag == 0)
{
b2Tick = uwTick;
pwm_mode_flag = 1;//5S后该标志位清零
}
break;
}
}
}
PWM的步进频率
需求:PWM输出频率在指定时间内均匀的升高或者降低。
基本思路
已知条件:PWM输出模式未切换时,pwmstepTick = uwTick;pwm_mode_flag置1,5s后又清零。5s后,(uwTick - pwmstepTick) = 5000
高频模式下,按下切换键5S后,ARR值从124变为249
低频模式下,按下切换键5S后,ARR值从249变为124
代码部分
/* PWM */
u32 pwmstepTick = 0;
void PWM_Process()
{
if(pwm_mode_flag == 0)//不在切换过程中
{
pwmstepTick = uwTick;//初始化步进频率的定时
if(pwm_mode == 0)//低频模式
{
TIM2->ARR = 250-1;
TIM2->CCR2 = (u16)(250.0f * pwm_duty / 100.0f);
}
else if(pwm_mode == 1)//高频模式
{
TIM2->ARR = 125-1;
TIM2->CCR2 = (u16)(125.0f * pwm_duty / 100.0f);
}
}
else//步进频率
{
if(pwm_mode == 0)//低频变高频
{
TIM2->ARR = 249 - (uwTick - pwmstepTick)/40;//5S后变成124
TIM2->CCR2 = (u16)( (250.0f - (uwTick - pwmstepTick) / 40) * pwm_duty / 100.0f );
}
else if(pwm_mode == 1)//高频变低频
{
TIM2->ARR = 124 + (uwTick - pwmstepTick)/40;//5S后变成249
TIM2->CCR2 = (u16)( (125 + (uwTick - pwmstepTick)/40) * pwm_duty / 100.0f);
}
}
}
只保存稳定在2S以上的频率
基本思路:
当freq_prev - freq的绝对值小于200,且freq > freq_prev | freq < freq_prev,开始计时,计时超过2s,则freq = freq_prev。
代码部分:
/* PWM捕获 */
u32 tim17_cnt;
u32 freq;
float v_prev = 0;
u32 lmvTick;
_Bool lmv_flag;//更新最大速度计时标志位
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
tim17_cnt = __HAL_TIM_GetCounter(&htim17);
__HAL_TIM_SetCounter(&htim17,0);
freq = 1e6/tim17_cnt;
v_prev = velocity;
velocity = (freq * 2.0 * 3.14f * para_r)/(100 * para_k);
HAL_TIM_IC_Start_IT(&htim17,TIM_CHANNEL_1);
}
/* PWM_Data */
void PWM_Data_Process()
{
if(pwm_mode == 0)
{
//保持时间不足2S的速度值纳入不计
if( abs( (int)(v_prev - velocity) ) < 200)//速度基本保持不变
{
if((u16)velocity > (u16)lmax_v)
{
if(lmv_flag == 0)
{
lmvTick = uwTick;//开始计时
lmv_flag = 1;
}
if( (uwTick - lmvTick >= 2000) && (lmv_flag == 1))
{
lmax_v = velocity;
lmv_flag = 0;//计时标志位
}
}
else
{
lmv_flag = 0;
}
}
else
{
lmv_flag = 0;
}
}
else
{
//保持时间不足2S的速度值纳入不计
if( abs( (int)(v_prev - velocity) ) < 200)//速度基本保持不变
{
if((u16)velocity > (u16)hmax_v)
{
if(lmv_flag == 0)
{
lmvTick = uwTick;//开始计时
lmv_flag = 1;
}
if( (uwTick - lmvTick >= 2000) && (lmv_flag == 1))
{
hmax_v = velocity;
lmv_flag = 0;//计时标志位
}
}
else
{
lmv_flag = 0;
}
}
else
{
lmv_flag = 0;
}
}
}