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

一、题目要求

在这里插入图片描述在这里插入图片描述在这里插入图片描述

二、代码部分

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闪烁标志
int  HH_Init=11,MM_Init=59,SS_Init=50;//时钟
int  hou=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;
}

按键处理

#define  KB1  (GPIOA->IDR&GPIO_Pin_0)
#define  KB2  (GPIOA->IDR&GPIO_Pin_8)
#define  KB3  (GPIOB->IDR&GPIO_Pin_1)
#define  KB4  (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⊙)。

发布了2 篇原创文章 · 获赞 8 · 访问量 2374

猜你喜欢

转载自blog.csdn.net/weixin_45849079/article/details/104387296