stm32|蓝桥杯嵌入式第十一届省赛模拟试题代码分享

一、题目要求 【stm32|蓝桥杯嵌入式第十一届省赛模拟试题代码分享】stm32|蓝桥杯嵌入式第十一届省赛模拟试题代码分享
文章图片
stm32|蓝桥杯嵌入式第十一届省赛模拟试题代码分享
文章图片
stm32|蓝桥杯嵌入式第十一届省赛模拟试题代码分享
文章图片

二、代码部分 1、 初始化代码 用到LED,LCD,KEY,i2c,USART和RTC的初始化,其中lcd初始化代码液晶驱动参考历程里面有,i2c初始化代码在参考程序里面有,只需自己写Write_AT24c02()和Read_AT24c02()函数。

//LED初始化 void LED_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD,ENABLE); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_All; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOC,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2; GPIO_Init(GPIOD,&GPIO_InitStructure); LED_Control(0x00); } //KEY初始化 void KEY_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_8; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_2; GPIO_Init(GPIOB,&GPIO_InitStructure); } //AT24c02 void Write_AT24c02(u8 add,u8 data) { I2CStart(); I2CSendByte(0xa0); I2CWaitAck(); I2CSendByte(add); I2CWaitAck(); I2CSendByte(data); I2CWaitAck(); I2CStop(); } unsigned char Read_AT24c02(u8 add) { u8 temp; I2CStart(); I2CSendByte(0xa0); I2CWaitAck(); I2CSendByte(add); I2CWaitAck(); I2CStart(); I2CSendByte(0xa1); I2CWaitAck(); temp=I2CReceiveByte(); I2CWaitAck(); I2CStop(); return temp; } //RTC 初始化 void RTC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); PWR_BackupAccessCmd(ENABLE); BKP_DeInit(); RCC_LSICmd(ENABLE); while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET) {} RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); RCC_RTCCLKCmd(ENABLE); RTC_WaitForSynchro(); RTC_WaitForLastTask(); RTC_ITConfig(RTC_IT_SEC, ENABLE); RTC_WaitForLastTask(); RTC_SetPrescaler(40000-1); RTC_WaitForLastTask(); BKP_TamperPinCmd(DISABLE); BKP_RTCOutputConfig(BKP_RTCOutputSource_Second); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } void Time_Adjust(uint32_t Tmp_HH,uint32_t Tmp_MM,uint32_t Tmp_SS) { RTC_WaitForLastTask(); RTC_SetCounter((Tmp_HH*3600 + Tmp_MM*60 + Tmp_SS)); RTC_WaitForLastTask(); } void Time_Display(uint32_t TimeVar) { if (RTC_GetCounter() == 0x0001517F) { RTC_SetCounter(0x0); RTC_WaitForLastTask(); } THH = TimeVar / 3600; TMM = (TimeVar % 3600) / 60; TSS = (TimeVar % 3600) % 60; } void RTC_IRQHandler(void)//中断处理函数 { if (RTC_GetITStatus(RTC_IT_SEC) != RESET) { RTC_ClearITPendingBit(RTC_IT_SEC); TimeDisplay = 1; RTC_WaitForLastTask(); } } //串口初始化 void STM_EVAL_COMInit( USART_InitTypeDef* USART_InitStruct) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA| RCC_APB2Periph_AFIO, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_Init(GPIOA, &GPIO_InitStructure); USART_Init(USART2, USART_InitStruct); USART_Cmd(USART2, ENABLE); } void USART2_Init(void) { USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; STM_EVAL_COMInit(&USART_InitStructure); USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); } //printf 重定向 int fputc(int ch, FILE *f) { USART_SendData(USART2, (uint8_t) ch); while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET) {} return ch; }

2、模块化代码分析 一些变量的定义
FlagStatus LCD_Update=RESET; //LCD更新标志,200毫秒更新一次 FlagStatus KEY_Flag=RESET; //按键读取标志,50毫秒读取一次 FlagStatus LED1_Flag=RESET; //LED1闪烁标志 intHH_Init=11,MM_Init=59,SS_Init=50; //时钟 inthou=12,min=0,sec=0; //报警时间,时分秒 u8 string[40]; u8 time_select=0,alarm_select=0; //时钟界面高亮显示,报警界面高亮显示,0,1,2对应时分秒 u8 tim_set_num=0; //时钟设置次数 u8 alarm_set_num=0; // 报警时间设置次数 u8 LED_States=0x00; //控制灯的闪烁 typedef enum { lcd_main,//主界面 lcd_rtc_setting,//时钟设置界面 lcd_alarm_setting,//报警设置界面 }_LCD_Enum; _LCD_Enum System_Mode=lcd_main;

LED的控制
void LED_Control(u16 val) { GPIOC->ODR=(~val)<<8; GPIOD->BSRR=GPIO_Pin_2; GPIOD->BRR=GPIO_Pin_2; }

按键处理
#defineKB1(GPIOA->IDR&GPIO_Pin_0) #defineKB2(GPIOA->IDR&GPIO_Pin_8) #defineKB3(GPIOB->IDR&GPIO_Pin_1) #defineKB4(GPIOB->IDR&GPIO_Pin_2)void Key_Read(void) { static u32 k1_sum=0,k2_sum=0,k3_sum=0,k4_sum=0; //按键1 if(KB1==0) { k1_sum++; if(k1_sum==1) { //主界面 if(System_Mode==lcd_main) { RCC_RTCCLKCmd(DISABLE); //暂停RTC时钟 System_Mode=lcd_rtc_setting; LCD_ClearLine(Line1); LCD_ClearLine(Line4); LCD_ClearLine(Line5); LCD_ClearLine(Line6); } //报警设置界面 else if(System_Mode==lcd_alarm_setting) { if(++alarm_select>=3) alarm_select=0; } //时钟设置界面 else if(System_Mode==lcd_rtc_setting) { RCC_RTCCLKCmd(ENABLE); tim_set_num+=1; Write_AT24c02(0x00,tim_set_num); System_Mode=lcd_main; Time_Adjust(HH_Init,MM_Init,SS_Init); printf("New:RTC:%.2d:%.2d:%.2d\r\n",HH_Init,MM_Init,SS_Init); } } } else { k1_sum=0; } 按键2 if(KB2==0) { k2_sum++; if(k2_sum==1) { //主界面 if(System_Mode==lcd_main) { LCD_Clear(Black); System_Mode=lcd_alarm_setting; } //始终设置界面 else if(System_Mode==lcd_rtc_setting) { if(++time_select>=3) time_select=0; } //报警设置界面 else if(System_Mode==lcd_alarm_setting) { alarm_set_num++; Write_AT24c02(0x01,alarm_set_num); Delay_Ms(5); Write_AT24c02(0x10,hou); Delay_Ms(5); Write_AT24c02(0x11,min); Delay_Ms(5); Write_AT24c02(0x12,sec); System_Mode=lcd_main; printf("New:Alarm:%.2d:%.2d:%.2d\r\n",hou,min,sec); } } } else { k2_sum=0; } /按键3 if(KB3==0) { k3_sum++; //短按键 if(k3_sum==1) { if(System_Mode==lcd_rtc_setting) { switch(time_select) { case 0:if(++HH_Init>=24) HH_Init=0; break; case 1:if(++MM_Init>=60) MM_Init=0; break; case 2:if(++SS_Init>=60) SS_Init=0; break; } } // if(System_Mode==lcd_alarm_setting) { switch(alarm_select) { case 0:if(++hou>=24) hou=0; break; case 1:if(++min>=60) min=0; break; case 2:if(++sec>=60) sec=0; break; } } } //长按键 if(k3_sum==20)//50ms 执行一次函数,20个50ms正好是1秒 { if(System_Mode==lcd_rtc_setting) { switch(time_select) { case 0:if(++HH_Init>=24) HH_Init=0; break; case 1:if(++MM_Init>=60) MM_Init=0; break; case 2:if(++SS_Init>=60) SS_Init=0; break; } } if(System_Mode==lcd_alarm_setting) { switch(alarm_select) { case 0:if(++hou>=24) hou=0; break; case 1:if(++min>=60) min=0; break; case 2:if(++sec>=60) sec=0; break; } } k3_sum=19; } } else { k3_sum=0; } //按键4 if(KB4==0) { k4_sum++; //短按键 if(k4_sum==1) { if(System_Mode==lcd_rtc_setting) { switch(time_select) { case 0:if(--HH_Init<0) HH_Init=23; break; case 1:if(--MM_Init<0) MM_Init=59; break; case 2:if(--SS_Init<0) SS_Init=59; break; } } if(System_Mode==lcd_alarm_setting) { switch(alarm_select) { case 0:if(--hou<0) hou=23; break; case 1:if(--min<0) min=59; break; case 2:if(--sec<0) sec=59; break; } } } //长按键 if(k4_sum==20) { //ê±??éè???£ê? if(System_Mode==lcd_rtc_setting) { switch(time_select) { case 0:if(--HH_Init<0) HH_Init=23; break; case 1:if(--MM_Init<0) MM_Init=59; break; case 2:if(--SS_Init<0) SS_Init=59; break; } } if(System_Mode==lcd_alarm_setting) { switch(alarm_select) { case 0:if(--hou<0) hou=23; break; case 1:if(--min<0) min=59; break; case 2:if(--sec<0) sec=59; break; } } k4_sum=19; } } else { k4_sum=0; } }

主界面显示函数
void LCD_MainShow(void) { LCD_DisplayStringLine(Line1,(u8 *)"MAIN"); sprintf((char *)string,"RTC:%.2d:%.2d:%.2d",THH,TMM,TSS); LCD_DisplayStringLine(Line4,(u8*)string); sprintf((char *)string,"time_select:%d",tim_set_num); LCD_DisplayStringLine(Line5,(u8*)string); sprintf((char *)string,"alarm_select:%d",alarm_set_num); LCD_DisplayStringLine(Line6,(u8*)string); if(LED1_Flag!=RESET) { LED1_Flag=RESET; LED_Control(LED_States^=0x01); //LED1闪烁 } }

时钟设置界面显示函数
高亮显示,主要由void LCD_DisplayChar(u8 Line, u16 Column, u8 Ascii); 函数来完成,这个函数一次只操纵一个字符,参数是以ASCII码传入的,三个入口参数分别为:行、列、数据的ASCII码。而且这个函数每次只能操纵一个字符,所以如果想要高亮显示大于等于2位数的时候,就需要对其进行个位、十位等的分离了,然后对每一位分别进行显示。并且要注意,数据是以ASCII码形式传入,所以显示数据变量时要加上’0’,或者+0x32。
void Set_DisPlay(void) { LCD_DisplayStringLine(Line1,(u8 *)"RTC-SETTING"); LCD_DisplayStringLine(Line4,(u8 *)"RTC:"); if(time_select==0) { LCD_SetTextColor(Red); } else { LCD_SetTextColor(White); } LCD_DisplayChar(Line4,319-127,HH_Init/10+'0'); LCD_DisplayChar(Line4,319-143,HH_Init%10+'0'); LCD_SetTextColor(White); LCD_DisplayChar(Line4,319-159,':'); if(time_select==1) { LCD_SetTextColor(Red); } else { LCD_SetTextColor(White); } LCD_DisplayChar(Line4,319-175,MM_Init/10+'0'); LCD_DisplayChar(Line4,319-191,MM_Init%10+'0'); LCD_SetTextColor(White); LCD_DisplayChar(Line4,319-207,':'); if(time_select==2) { LCD_SetTextColor(Red); } else { LCD_SetTextColor(White); } LCD_DisplayChar(Line4,319-223,SS_Init/10+'0'); LCD_DisplayChar(Line4,319-239,SS_Init%10+'0'); LCD_SetTextColor(White); LED_Control(0x02); //LED2亮 }

报警设置界面显示函数
void ALARM_DisPlay(void) { LCD_DisplayStringLine(Line1,(u8 *)"ALARM-SETTING"); LCD_DisplayStringLine(Line4,(u8 *)"ALARM:"); if(alarm_select==0)//高亮时 { LCD_SetTextColor(Red); } else { LCD_SetTextColor(White); } LCD_DisplayChar(Line4,319-127,hou/10+'0'); LCD_DisplayChar(Line4,319-143,hou%10+'0'); LCD_SetTextColor(White); LCD_DisplayChar(Line4,319-159,':'); if(alarm_select==1) { LCD_SetTextColor(Red); } else { LCD_SetTextColor(White); } LCD_DisplayChar(Line4,319-175,min/10+'0'); LCD_DisplayChar(Line4,319-191,min%10+'0'); LCD_SetTextColor(White); LCD_DisplayChar(Line4,319-207,':'); if(alarm_select==2) { LCD_SetTextColor(Red); } else { LCD_SetTextColor(White); } LCD_DisplayChar(Line4,319-223,sec/10+'0'); LCD_DisplayChar(Line4,319-239,sec%10+'0'); LCD_SetTextColor(White); LED_Control(0x04); //LED3亮 }

滴答定时器部分
void SysTick_Handler(void)//1ms进一次中断 { static u32 lcd_count=0,key_count=0,led1_count=0; if(TimingDelay>0) TimingDelay--; led1_count++; lcd_count++; key_count++; check_count++; if(led1_count>=1000) { led1_count=0; LED1_Flag=SET; } if(key_count>=50) { key_count=0; KEY_Flag=SET; } if(lcd_count>=200) { lcd_count=0; LCD_Update=SET; } }

主函数部分
int main(void) { SysTick_Config(SystemCoreClock/1000); STM3210B_LCD_Init(); RTC_Configuration(); i2c_init(); LED_Init(); KEY_Init(); USART2_Init(); LCD_Clear(Black); LCD_SetBackColor(Black); LCD_SetTextColor(White); Time_Adjust(HH_Init,MM_Init,SS_Init); tim_set_num=Read_AT24c02(0x00); Delay_Ms(5); alarm_set_num=Read_AT24c02(0x01); Delay_Ms(5); hou=Read_AT24c02(0x10); Delay_Ms(5); min=Read_AT24c02(0x11); Delay_Ms(5); sec=Read_AT24c02(0x12); while(1) { if(KEY_Flag!=RESET) { KEY_Flag=RESET; Key_Read(); } if(LCD_Update!=RESET) { LCD_Update=RESET; if(System_Mode==lcd_main)LCD_MainShow(); if(System_Mode==lcd_rtc_setting)Set_DisPlay(); if(System_Mode==lcd_alarm_setting) ALARM_DisPlay(); } if (TimeDisplay == 1) { /* Display current time */ Time_Display(RTC_GetCounter()); TimeDisplay = 0; } } }

如果想RTC时钟到达设定的报警时间时蜂鸣器报警,可以设 u32 DingShi=hou3600+min60+sec; 在主函数while(1)中判断DingShi是否与RTC_GetCounter()相等,若相等,蜂鸣器响,否则不响;
以上就是我对这个题的解答,若有不足之处或是有好的建议,欢迎留言(⊙o⊙)。

    推荐阅读