第十二届-嵌入式设计与开发科目模拟试题
代码工程和题目PDF地址: https://github.com/Lxiangrui/Simulation-of-the-12th-Blue-Bridge-Cup
1、题目内容
2、需求分析
1、硬件部分,先看需要哪些模块,仅仅有ADC、GPIO、USART!!所以配置部分应该没有什么问题。
2、通读全题,理解需求,划分先后,发现该题ADC是核心,按键和串口其次,最后才是LED,当然还有LCD。
3、逻辑部分,主要逻辑部分在于如何实现定时器的开始、停止、重新开始等操作、其次就是简单的按键和串口控制参数变化。
核心逻辑:
重点的,对于如何实现定时器的开始、停止、重新开始等操作,我就单独展开说一下吧,我首先想到的是利用数组存储历史电压值,来判断是否满足条件。比如定时器的(重新)开始的点,通过题目来看,就是电压值上升,并且经过Vmin的时刻,我就通过判断历史值小于Vmin,并且瞬时值大于Vmax,就能很好的,判断定时器的开始的时刻了。结束功能同理。
3、相关代码
主函数
负责模块初始化、界面的显示和切换,按键处理,串口处理,以及逻辑函数等的调用
int main(void)
{
SysTick_Config(SystemCoreClock/1000);
Delay_Ms(200);
Init_adc();
Init_usart();
Init_key();
Init_led();
STM3210B_LCD_Init();
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
Ctro_led(ledall,0);
history_voltage[0] = volt_adc();
history_voltage[1] = volt_adc();
while(1){
if(flag_UI) UI_PARA();
else UI_DATA();
UART_handle();
determine_tim();
LED_handle();
}
}
获取电压函数
更新电压瞬时值,并且保存历史值,为了使程序运行良好,采用了10ms一次的更新
void to_obtain_voltage(){
if(time_ms%10 == 0){
history_voltage[1] = history_voltage[0];
history_voltage[0] = volt_adc();}
}
定时器模式函数
void determine_tim(){
if((history_voltage[0] > Vmin)&&(history_voltage[1] < Vmin)){
Tim_flag = 1;
time_s = 0;
}
if((history_voltage[0] > Vmax)&&(history_voltage[1] < Vmax)){
Tim_flag = 0;
}
}
UI界面函数
void UI_DATA(){
LCD_DisplayStringLine(Line0,(unsigned char *)" Data");
sprintf(disbuff," V:%.2fV ", volt_adc());
if(time_ms%50 > 40) LCD_DisplayStringLine(Line2,(unsigned char *)disbuff);
sprintf(disbuff," T:%ds ",time_s);
LCD_DisplayStringLine(Line3,(unsigned char *)disbuff);
to_obtain_voltage();
}
void UI_PARA(){
LCD_DisplayStringLine(Line0,(unsigned char *)" Para");
sprintf(disbuff," Vmax:%.1fV ", Vmax);
LCD_DisplayStringLine(Line2,(unsigned char *)disbuff);
sprintf(disbuff," Vmin:%.1fV ", Vmin);
LCD_DisplayStringLine(Line3,(unsigned char *)disbuff);
}
LED控制函数
没什么讲的,按照不同标志位,控制LED亮灭
void LED_handle(){
if(Tim_flag == 1) Ctro_led(led1,1);
else Ctro_led(led1,0);
if(led2_flag == 1) Ctro_led(led2,1);
else Ctro_led(led2,0);
if(led3_flag == 1) Ctro_led(led3,1);
else Ctro_led(led3,0);
}
串口处理函数
这里我使用的三个嵌套的if来判断串口设置的值是否满足条件,是因为但是我不想写括号,而且那样会使得if那一行很长。但总的来说三个if嵌套着写,代码还是变多了。。因为后面发现,题目要求如果不满足条件,LED3会常亮,所以加了三个else,如果一开始就使用一个if并行判断,只需要一个else就好了😂,所以还是缺少了大局观,没有考虑很仔细。
void UART_handle(){
if(RXOVER){
int i;
LCD_DisplayStringLine(Line6,(unsigned char *)RxBuffer1);
uvmax = (RxBuffer1[0]-'0') + (RxBuffer1[2]-'0')*0.1;
uvmin = (RxBuffer1[4]-'0') + (RxBuffer1[6]-'0')*0.1;
if(uvmax-uvmin-1>0){
if((uvmax>0)&&(uvmax<3.3)){
if((uvmin>0)&&(uvmin<3.3)){
Vmax = uvmax;
Vmin = uvmin;
led3_flag = 0;
}
else led3_flag = 1;
}
else led3_flag = 1;
}
else led3_flag = 1;
for(i=0;i<100;i++) RxBuffer1[i] = 0;
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
}
}
按键中断处理函数
按键中断处理函数,我把它们都放到了main.c中,这样就不用extern 很多变量传递了。其次是改题目并没有使用b4按键,我配了,虽然只是几行代码,但是还是浪费了时间。还有就是按键逻辑处理的时候,也是犯了和串口处理程序中一样的错,使得程序冗余。
tips:
题目要求如果按键设置的值不合理,就不会更新按键的值,我的思路是,每次进入按键设置界面时,就保存现在的电压上下限,然后按下按键时,是改的真实的电压上下限,然后在按下b1时,切换回数据界面时,判断现在的电压上下限是否满足条件,如果不满足就将开始保存的电压上下限赋值回去,并且控制LED点亮,反之满足条件就关闭LED,并保存电压上下限。
当然还有那种设置针对于按键模式内的电压上下限,那样的话需要在模式切换的时候来回赋值,代码比较多,我就没用那种了。
void EXTI0_IRQHandler(void)
{
static char flag_panduan;
if(EXTI_GetITStatus(EXTI_Line0) != RESET)
{
i= 0xffff;
while(i--);
if(flag_UI == 0){
kvmax = Vmax;
kvmin = Vmin;
}
flag_UI=!flag_UI;
if(flag_UI == 0){
flag_panduan = 1;
}
if(flag_panduan == 1){
if(Vmax-Vmin-1>0){
if((Vmax>0)&&(Vmax<3.3)){
if((Vmin>0)&&(Vmin<3.3)){
led2_flag = 0;
}
else{
Vmax = kvmax;
Vmin = kvmin;
led2_flag = 1;
}
}
else{
Vmax = kvmax;
Vmin = kvmin;
led2_flag = 1;
}
}
else{
Vmax = kvmax;
Vmin = kvmin;
led2_flag = 1;
}
flag_panduan = 0;
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line8) != RESET)
{
i= 0xffff;
while(i--);
if(flag_UI == 1) Vmax+=0.1;
if(Vmax>3.3) Vmax = 0;
EXTI_ClearITPendingBit(EXTI_Line8);
}
}
void EXTI1_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line1) != RESET)
{
i= 0xffff;
while(i--);
if(flag_UI == 1) Vmin+=0.1;
if(Vmin>3.3) Vmin = 0;
EXTI_ClearITPendingBit(EXTI_Line1);
}
}
SYStick函数
这里使用systick来驱动定时,同时还用来控制adc采样时间,以及延时,还有LCD刷新率,对于蓝桥杯真的很方便,但是实际应用不知道好不好哦.
void SysTick_Handler(void)
{
time_ms++;
if(time_ms % 1000 == 0){
if(Tim_flag) time_s++;
time_ms = 0;
}
TimingDelay--;
}
} }
### SYStick函数
这里使用systick来驱动定时,同时还用来控制adc采样时间,以及延时,还有LCD刷新率,对于蓝桥杯真的很方便,但是实际应用不知道好不好哦.
```c
void SysTick_Handler(void)
{
time_ms++;
if(time_ms % 1000 == 0){
if(Tim_flag) time_s++;
time_ms = 0;
}
TimingDelay--;
}
|