一、题目要求 【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⊙)。
推荐阅读
- 嵌入式|【嵌入式linux】U盘自动识别和挂载
- 嵌入式|想成为嵌入式程序员应知道的0x10个基本问题(面试必备)
- 学员嵌入式Max面试经历分享
- 通信与电子|(实用入门)4G模块SIM7600CE-L常用指令
- verilog实战|基于RAM实现乒乓buffer
- 从物理定律到编程语言|【感性认识】嵌入式开发有何不同
- 单片机|猿创征文 | 实验一 单片机keil51软件使用及IO控制