一、分析
本届的风格又变了一番,但是难度也降低了些。
又是考察了 PWM 和 ADC。
第八、九届也考察了 PWM。建议先复习这两届,再回来模拟。
LCD的显示也提了额外的要求。
1. 功能概述
- 电位器 R37 输出的模拟电压信号
- PA6输出频率固定,占空比可调节
- PA7输出频率固定,占空比可调节
- 完成 B1、B2、B3、B4 按键动作
- 完成 LCD 显示数据和参数
2. 性能要求
- 数据显示界面下电压值更新时间:<= 0.1 秒
- PA6、PA7输出信号占空比跟随相应时间:<=1秒
- 按键相应时间:<=0.1 秒
- 输出频率精度:<=5%
- 输出占空比精度:<=5%
本届把性能要求单独列出来,好看多了。
3. 运行模式
这部分是关键,和往届考察的PWM不同
1)自动模式:PA6 和 PA7 输出信号占空比相同,
当 R37_Volt = 0,PA6 和 PA7 持续输出低电平。
当 R37_Volt = 3.3,PA6 和 PA7 持续输出高电平。
2)手动模式:PA6、PA7 输出信号占空比通过按键控制,与 R37_Volt 无关
这部分的伪代码,先把下面的先搞定,再来写这里的。
伪代码
PWM_state_manu = 0;
PWM_state_auto = 0;
void Running_mode(){if(D_state == Data_Disp):if(mode == AUTO){if(Key_Down == 3){if(PWM_state_auto == 0){// 80M/(80*10K)=100TIM_AUTORELOAD(&htim3, 9999);// 80M/(80*5K) =200TIM_AUTORELOAD(&htim17, 4999);TIM_COMPARE(&htim3, Channel_1, (unsigned int)(10000*((R37_Volt)/3.3)));TIM_COMPARE(&htim17, Channel_1, (unsigned int)(5000*((R37_Volt)/3.3)));PWM_state_auto = 1;}else if(PWM_state_auto == 1){// 80M/(80*10K)=100TIM_AUTORELOAD(&htim17, 9999);// 80M/(80*5K) =200TIM_AUTORELOAD(&htim3, 4999);TIM_COMPARE(&htim17, Channel_1, (unsigned int)(10000*((R37_Volt)/3.3)));TIM_COMPARE(&htim3, Channel_1, (unsigned int)(5000*((R37_Volt)/3.3)));PWM_state_auto = 0;}}}else if(mode == MANU){//切换PA6和PA7的频率if(Key_Down == 3){if (PWM_state_manu == 0){// 80M/(80*10K)=100TIM_AUTORELOAD(&htim3, 9999);// 80M/(80*5K) =200TIM_AUTORELOAD(&htim17, 4999);//频率改变后,占空比也要跟随,毕竟跟周期有关TIM_COMPARE(&htim3, Channel_1, (100*PA6_Duty));TIM_COMPARE(&htim17, Channel_1, (50*PA6_Duty));PWM_state_manu = 1;}else if(PWM_state_manu == 1){// 80M/(80*10K)=100TIM_AUTORELOAD(&htim17, 9999);// 80M/(80*5K) =200TIM_AUTORELOAD(&htim3, 4999);//频率改变后,占空比也要跟随,毕竟跟周期有关TIM_COMPARE(&htim17, Channel_1, (100*PA6_Duty));TIM_COMPARE(&htim3, Channel_1, (50*PA6_Duty));PWM_state_manu = 0;}}}}
4. LCD 显示界面
本届直接把像素位置给标出来了,严格要求显示的细节。
1)数据显示界面
- Data
- 电压
- 模式:自动或手动
2)参数显示界面
- Para
- PA6占空比
- PA7占空比
3)显示颜色
- 背景色:黑
- 前景色:白
伪代码
typedef enum{Data_Disp,Para_Disp
} Disp_State;typedef enum{AUTO,MANU
} Mode;const char* ModeStrings[] = {"AUTO","MANU"
};Disp_State D_state = Data_Disp;
Mode mode = AUTO;
float PA6_Duty, PA7_Duty;
float R37_Volt;
void Led_Proc(){//数据显示界面if(D_state == Data_Disp){LCD_display("Data");LCD_display("V:%f",R37_Volt);LCD_display("Mode",ModeStrings[mode]);}else if(D_state == Para_Disp){LCD_Clear(Black);LCD_display("Para");LCD_display("PA6:%f%%", PA6_Duty);LCD_display("PA6:%f%%", PA7_Duty);}
}
5. 按键功能
1)B1:界面切换
2)B2:参数设置下,手动模式下,PA6占空比加10%,数值边界(10%-90%),需要设置参数循环。
3)B3:参数设置下,手动模式下,PA7占空比加10%,数值边界(10%-90%),需要设置参数循环。
4)B4:切换模式
5)B3:数据显示下,互换PA6和PA7输出频率
伪代码
unsigned int Key_Down;
Key_Proc(){//消抖不写了//按键模版不写了switch (Key_Down){case 1:if(D_state == Data_Disp){LCD_Clear(Black);D_state = Para_Disp;}else if(D_state == Para_Disp){LCD_Clear(Black);D_state = Data_Disp;}break;case 2:if(D_state == Para_Disp){if(mode == MANU){if(PA6_Duty < 90){PA6_Duty += 10;}else if(PA6_Duty = 90)PA6_Duty = 10;}}break;case 3:if(D_state == Para_Disp){if(mode == MANU){if(PA7_Duty < 90){PA7_Duty += 10;}else if(PA7_Duty = 90)PA7_Duty = 10;}}else if (D_state == Data_Disp){//切换频率这块单独写个函数}break;case 4:if(mode == AUTO)mode = MANU;else mode == AUTO;break;}
}
6. LED 指示灯
1)自动模式,LD1亮;手动模式,LD1灭。
2)数据界面,LD2亮;参数界面,LD2灭。
void Led_Proc(){if(mode == AUTO){ucled |= 0x01;}else if(mode == MANU){ucled &= ~0x01;}if(D_state == Data_Disp)ucled |= 0x02;else if(D_state == Para_Disp)ucled &= ~0x02;
}
7. 初始状态说明
1)自动模式
2)数据界面
3)10%占空比
4)PA6_f = 100Hz,PA7_f = 200Hz
占空比和频率在 CubeMx 调整。
二、CubeMx
Key 、LED 和 ADC 就不重复写了,重点是 PWM。
PWM
按图中配置的话,
那么此时改动 Pulse = 100,那么Duty = 100/999+1 = 10%
当然这些都是初始值,除了时钟频率和 PSC保持不变,其它都要在代码中改动。
当然 TIM17 和 TIM3 也一样。
三、完整代码编写
1. 全局变量
/* USER CODE BEGIN Includes */
#include "lcd.h"
#include "stdio.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
typedef enum{Data_Disp,Para_Disp
} Disp_State;typedef enum{AUTO,MANU
} MODE;const char* ModeString[] = {"AUTO","MANU"
};Disp_State D_state = Data_Disp;
MODE mode = AUTO;
/* USER CODE END PTD *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV */uint16_t Lcd_Disp_Str[21];
float R37_Volt;
uint8_t PA6_Duty=10, PA7_Duty=10;
uint8_t Key_val, Key_up, Key_down, Key_old;
uint8_t ucled;uint8_t PWM_state_manu = 0;
uint8_t PWM_state_auto = 0;
__IO uint16_t uwTick_Set_Lcd = 0;
__IO uint16_t uwTick_Set_Key = 0;
__IO uint16_t uwTick_Set_Led = 0;
__IO uint16_t uwTick_Set_PWM = 0;/* USER CODE END PV */
2. 主函数
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_ADC2_Init();MX_TIM3_Init();MX_TIM17_Init();/* USER CODE BEGIN 2 */LCD_Init();LCD_Clear(Black);LCD_SetBackColor(Black);LCD_SetTextColor(White);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */Lcd_Proc();Key_Proc();Led_Proc();Running_mode();/* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
3. 显示
void Lcd_Proc(){if((uwTick_Set_Lcd - uwTick) < 100)return;uwTick = uwTick_Set_Lcd;R37_Volt = (((float)(Get_ADC2())/4096)*3.3);if(D_state == Data_Disp){sprintf((char*) Lcd_Disp_Str, " Data");LCD_DisplayStringLine(Line0, Lcd_Disp_Str);sprintf((char*) Lcd_Disp_Str, " V:%4.2fV", R37_Volt);LCD_DisplayStringLine(Line2, Lcd_Disp_Str);sprintf((char*) Lcd_Disp_Str, " Mode:%s", ModeString[mode]);LCD_DisplayStringLine(Line4, Lcd_Disp_Str);}else if(D_state == Para_Disp){sprintf((char*) Lcd_Disp_Str, " Para");LCD_DisplayStringLine(Line0, Lcd_Disp_Str);sprintf((char*) Lcd_Disp_Str, " PA6:%02d%%", (unsigned int)PA6_Duty);LCD_DisplayStringLine(Line2, Lcd_Disp_Str);sprintf((char*) Lcd_Disp_Str, " PA7:%02d%%", (unsigned int)PA7_Duty);LCD_DisplayStringLine(Line4, Lcd_Disp_Str);}
}
4. 按键
void Key_Proc(){if((uwTick_Set_Key - uwTick) < 100)return;uwTick = uwTick_Set_Key;Key_val = Key_Scan();Key_up = Key_val & (Key_val ^ Key_old);Key_down = ~Key_val & (Key_val ^ Key_old);Key_old = Key_val;switch(Key_down){case 1:if(D_state == Data_Disp){LCD_Clear(Black);D_state = Para_Disp;}else if(D_state == Para_Disp){LCD_Clear(Black);D_state = Data_Disp;}break;case 2:if(D_state == Para_Disp){if(mode == MANU){if(PA6_Duty < 90){PA6_Duty += 10;}else if(PA6_Duty == 90)PA6_Duty = 10;}}break;case 3:if(D_state == Para_Disp){if(mode == MANU){if(PA7_Duty < 90){PA7_Duty += 10;}else if(PA7_Duty == 90)PA7_Duty = 10;}}break;case 4:if(mode == AUTO)mode = MANU;else mode = AUTO;break;}
}
5. LED
void Led_Proc(){if((uwTick_Set_Led - uwTick) < 100)return;uwTick = uwTick_Set_Led;if(mode == AUTO){ucled |= 0x01;}else if(mode == MANU){ucled &= ~(0x01);}if(D_state == Data_Disp)ucled |= 0x02;else if(D_state == Para_Disp)ucled &= ~(0x02);Led_Disp(ucled);
}
6. PWM
void Running_mode(){if((uwTick_Set_PWM - uwTick) < 100)return;uwTick = uwTick_Set_PWM;if(D_state == Data_Disp){if(Key_down == 3){if(mode == AUTO){if(PWM_state_auto == 0){//80M/(80*10K)=100__HAL_TIM_SET_AUTORELOAD(&htim3, 9999);// 80M/(80*5K) =200__HAL_TIM_SET_AUTORELOAD(&htim17, 4999);__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, (unsigned int)(10000*((R37_Volt)/3.3)));__HAL_TIM_SET_COMPARE(&htim17, TIM_CHANNEL_1, (unsigned int)(5000*((R37_Volt)/3.3)));PWM_state_auto = 1;}if(PWM_state_auto == 1){//80M/(80*10K)=100__HAL_TIM_SET_AUTORELOAD(&htim17, 9999);// 80M/(80*5K) =200__HAL_TIM_SET_AUTORELOAD(&htim3, 4999);__HAL_TIM_SET_COMPARE(&htim17, TIM_CHANNEL_1, (unsigned int)(10000*((R37_Volt)/3.3)));__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, (unsigned int)(5000*((R37_Volt)/3.3)));PWM_state_auto = 0;}}切换PA6和PA7的频率else if(mode == MANU){if(PWM_state_manu == 0){__HAL_TIM_SET_AUTORELOAD(&htim3, 9999);__HAL_TIM_SET_AUTORELOAD(&htim17, 4999);//频率改变后,占空比也要跟随,毕竟跟周期有关__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, (100*PA6_Duty));__HAL_TIM_SET_COMPARE(&htim17, TIM_CHANNEL_1, (50*PA6_Duty));PWM_state_manu = 1; }else if(PWM_state_manu == 1){__HAL_TIM_SET_AUTORELOAD(&htim17, 9999);__HAL_TIM_SET_AUTORELOAD(&htim3, 4999);//频率改变后,占空比也要跟随,毕竟跟周期有关__HAL_TIM_SET_COMPARE(&htim17, TIM_CHANNEL_1, (100*PA6_Duty));__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, (50*PA6_Duty));PWM_state_manu = 0; }}}
}
}
7. BSP
这块不赘述了,背就完了