多功能电子钟

【嵌入式课程设计】基于STM32F4的多功能电子钟设计

一、课程设计目的

1、进一步掌握嵌入式系统课程所学STM32F4各功能模块的工作原理;
2、进一步熟练掌握STM32F4各功能模块的配置与使用方法;
3、进一步熟练掌握开发环境Keil MDK5的使用与程序调试技巧;
4、自学部分功能模块的原理、配置与使用方法,培养自学能力;
5、培养设计复杂嵌入式应用软、硬件系统的分析与设计能力。

二、课程设计内容

1、查阅资料,自学STM32F4的RTC模块,完成RTC的配置;
2、查阅资料,学习STM32F4与LCD的接口设计,完成LCD液晶屏驱动程序的设计,将时间、日期、星期等日历信息显示在LCD上;
3、能进行正常的日期、时间、星期显示;
4、有校时、校分功能,可以使用按键校时、校分,也可以通过串口调试助手由主机传送时间参数进行校时、校分;
5、能进行整点报时并有闹钟功能,闹钟时间可以设置多个;
6、系统关机后时间能继续运行,下次开机时间应准确;
7、查阅资料,学习STM32F4内部温度传感器的配置,采集、计算片内温度并显示在LCD上;

三、实验方案分析与设计

此模块描述课程设计中用到的硬件资源或模块工作原理,硬件电路的连接、模块的库函数配置方法(用到的主要库函数、配置步骤等)。

3.1 RTC实时时钟

3.1.1 工作原理

实时时钟 (RTC) 是一个独立的 BCD 定时器/计数器。RTC 提供一个日历时钟、两个可编程闹钟中断,以及一个具有中断功能的周期性可编程唤醒标志。RTC 还包含用于管理低功耗模式的自动唤醒单元。两个 32 位寄存器包含二进码十进数格式 (BCD) 的秒、分钟、小时(12 或 24 小时制)、星期几、日期、月份和年份。此外,还可提供二进制格式的亚秒值。系统可以自动将月份的天数补偿为 28、29(闰年)、30 和 31 天。并且还可以进行夏令时补偿。其它 32 位寄存器还包含可编程的闹钟亚秒、秒、分钟、小时、星期几和日期。此外,还可以使用数字校准功能对晶振精度的偏差进行补偿。上电复位后,所有 RTC 寄存器都会受到保护,以防止可能的非正常写访问。无论器件状态如何(运行模式、低功耗模式或处于复位状态),只要电源电压保持在工作范围内,RTC 便不会停止工作。RTC工作原理图如下图1所示。
图1 RTC工作原理框图

3.2 温度传感器

1、温度传感器可用于测量器件的环境温度 (TA)
对于STM32F40x和STM32F41x器件,温度传感器内部连接到ADC1_IN16通道,而ADC1用于将传感器输出电压转换为数字值。
对于STM32F42x 和 STM32F43x 器件,温度传感器内部连接到与VBAT共用的输入通道ADC1_IN18:ADC1_IN18用于将传感器输出电压或 VBAT 转换为数字值。一次只能选择一个转换(温度传感器或 VBAT)。同时设置了温度传感器和VBAT转换时,将只进行VBAT转换。不使用时可将传感器置于掉电模式。
图2 温度传感器框图

3.3 外部中断/ 事件控制器 (EXTI)

外部中断/事件控制器包含多达23个用于产生事件/中断请求的边沿检测器。每根输入线都可单独进行配置,以选择类型(中断或事件)和相应的触发事件(上升沿触发、下降沿触发或边沿触发)。每根输入线还可单独屏蔽。挂起寄存器用于保持中断请求的状态线。
图3 外部中断/事件控制器框图

3.4 通用同步异步收发器 (USART)

3.4.1 工作原理

通用同步异步收发器 (USART) 能够灵活地与外部设备进行全双工数据交换,满足外部设备对工业标准 NRZ 异步串行数据格式的要求。USART 通过小数波特率发生器提供了多种波特率。它支持同步单向通信和半双工单线通信;还支持 LIN(局域互连网络)、智能卡协议与 IrDA(红外线数据协会)SIR ENDEC 规范,以及调制解调器操作 (CTS/RTS)。而且,它还支持多处理器通信。通过配置多个缓冲区使用 DMA 可实现高速数据通信。

3.5 BEEP

3.5.1 工作原理

蜂鸣器是一种一体化结构的电子讯响器。开发板板载的蜂鸣器是电磁式的有源蜂鸣器。我们是通过三极管扩流后再驱动蜂鸣器,IO 只需要提供不到 1mA 的电流就足够了。

四、具体实现过程描述

4.1 RTC具体配置代码

//RTC时间设置
ErrorStatus RTC_Set_Time(u8 hour,u8 min,u8 sec,u8 ampm)
{
   
	RTC_TimeTypeDef RTC_TimeTypeInitStructure;	
	RTC_TimeTypeInitStructure.RTC_Hours=hour;
	RTC_TimeTypeInitStructure.RTC_Minutes=min;
	RTC_TimeTypeInitStructure.RTC_Seconds=sec;
	RTC_TimeTypeInitStructure.RTC_H12=ampm;
	return RTC_SetTime(RTC_Format_BIN,&RTC_TimeTypeInitStructure);
}

//RTC日期设置
ErrorStatus RTC_Set_Date(u8 year,u8 month,u8 date,u8 week)
{
   
	RTC_DateTypeDef RTC_DateTypeInitStructure;
	RTC_DateTypeInitStructure.RTC_Date=date;
	RTC_DateTypeInitStructure.RTC_Month=month;
	RTC_DateTypeInitStructure.RTC_WeekDay=week;
	RTC_DateTypeInitStructure.RTC_Year=year;
	return RTC_SetDate(RTC_Format_BIN,&RTC_DateTypeInitStructure);
}

//RTC初始化
u8 My_RTC_Init(void)
{
   
	RTC_InitTypeDef RTC_InitStructure;
	u16 retry=0X1FFF; 
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//使能PWR时钟
	PWR_BackupAccessCmd(ENABLE);	//使能后备寄存器访问 
	if(RTC_ReadBackupRegister(RTC_BKP_DR0)!=0x5050)		//是否第一次配置?
	{
   
		RCC_LSEConfig(RCC_LSE_ON);//LSE 开启    
		while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)	//检查指定的RCC标志位设置与否,等待低速晶振就绪
			{
   
			retry++;
			delay_ms(10);
			}
		if(retry==0)return 1;		//LSE 开启失败. 
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);		//设置RTC时钟(RTCCLK),选择LSE作为RTC时钟    
		RCC_RTCCLKCmd(ENABLE);	//使能RTC时钟 

        RTC_InitStructure.RTC_AsynchPrediv = 0x7F;//RTC异步分频系数(1~0X7F)
        RTC_InitStructure.RTC_SynchPrediv  = 0xFF;//RTC同步分频系数(0~7FFF)
        RTC_InitStructure.RTC_HourFormat   = RTC_HourFormat_24;//RTC设置为,24小时格式
        RTC_Init(&RTC_InitStructure);
 
		RTC_Set_Time(23,59,56,RTC_H12_AM);	//设置时间
		RTC_Set_Date(14,5,5,1);		//设置日期
	 
		RTC_WriteBackupRegister(RTC_BKP_DR0,0x5050);	//标记已经初始化过了
	} 
	return 0;
}
//设置闹钟时间(按星期闹铃,24小时制)
//week:星期几(1~7) @ref  RTC_Alarm_Definitions
//hour,min,sec:小时,分钟,秒钟
void RTC_Set_AlarmA(u8 week,u8 hour,u8 min,u8 sec)
{
    
	EXTI_InitTypeDef   EXTI_InitStructure;
	RTC_AlarmTypeDef RTC_AlarmTypeInitStructure;
	RTC_TimeTypeDef RTC_TimeTypeInitStructure;
	RTC_AlarmCmd(RTC_Alarm_A,DISABLE);//关闭闹钟A 
	
    RTC_TimeTypeInitStructure.RTC_Hours=hour;//小时
	RTC_TimeTypeInitStructure.RTC_Minutes=min;//分钟
	RTC_TimeTypeInitStructure.RTC_Seconds=sec;//秒
	RTC_TimeTypeInitStructure.RTC_H12=RTC_H12_AM;
  
	RTC_AlarmTypeInitStructure.RTC_AlarmDateWeekDay=week;//星期
	RTC_AlarmTypeInitStructure.RTC_AlarmDateWeekDaySel=RTC_AlarmDateWeekDaySel_WeekDay;//按星期闹
	RTC_AlarmTypeInitStructure.RTC_AlarmMask=RTC_AlarmMask_None;//精确匹配星期,时分秒
	RTC_AlarmTypeInitStructure.RTC_AlarmTime=RTC_TimeTypeInitStructure;
    RTC_SetAlarm(RTC_Format_BIN,RTC_Alarm_A,&RTC_AlarmTypeInitStructure);
	RTC_ClearITPendingBit(RTC_IT_ALRA);//清除RTC闹钟A的标志
    EXTI_ClearITPendingBit(EXTI_Line17);//清除LINE17上的中断标志位 
	RTC_ITConfig(RTC_IT_ALRA,ENABLE);//开启闹钟A中断
	RTC_AlarmCmd(RTC_Alarm_A,ENABLE);//开启闹钟A 
	
EXTI_InitStructure.EXTI_Line = EXTI_Line17;//LINE17
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发 
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能LINE17
    EXTI_Init(&EXTI_InitStructure);//配置

	NVIC_InitStructure.NVIC_IRQChannel = RTC_Alarm_IRQn; 
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级1
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
    NVIC_Init(&NVIC_InitStructure);//配置
}
//cnt:自动重装载值.减到0,产生中断.
void RTC_Set_WakeUp(u32 wksel,u16 cnt)
{
    
	EXTI_InitTypeDef   EXTI_InitStructure;
	RTC_WakeUpCmd(DISABLE);//关闭WAKE UP
	RTC_WakeUpClockConfig(wksel);//唤醒时钟选择
	RTC_SetWakeUpCounter(cnt);//设置WAKE UP自动重装载寄存器
	RTC_ClearITPendingBit(RTC_IT_WUT); //清除RTC WAKE UP的标志
    EXTI_ClearITPendingBit(EXTI_Line22);//清除LINE22上的中断标志位 
	RTC_ITConfig(RTC_IT_WUT,ENABLE);//开启WAKE UP 定时器中断
	RTC_WakeUpCmd( ENABLE);//开启WAKE UP 定时器 
	
EXTI_InitStructure.EXTI_Line = EXTI_Line22;//LINE22
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发 
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能LINE22
    EXTI_Init(&EXTI_InitStructure);//配置
 	
NVIC_InitStructure.NVIC_IRQChannel = RTC_WKUP_IRQn; 
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级1
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
    NVIC_Init(&NVIC_InitStructure);//配置
}

//RTC闹钟中断服务函数
void RTC_Alarm_IRQHandler(void)
{
       
	if(RTC_GetFlagStatus(RTC_FLAG_ALRAF)==SET)//ALARM A中断?
	{
   
		RTC_ClearFlag(RTC_FLAG_ALRAF);//清除中断标志
		sign=1;
		printf("ALARM A!\r\n");
					x=clockw[0];
					clockw[0]=clockw[1];
					clockw[1]=x;
					x=clockh[0];
					clockh[0]=clockh[1];
					clockh[1]=x;
					x=clockm[0];
					clockm[0]=clockm[1];
					clockm[1]=x;
					x=clocks[0];
					clocks[0]=clocks[1];
					clocks[1]=x;
					x=clock[0];
					clock[0]=clock[1];
					clock[1]=x;
					RTC_Set_AlarmA(clockw[0],clockh[0],clockm[0],clocks[0]);
	}   
	EXTI_ClearITPendingBit(EXTI_Line17);	//清除中断线17的中断标志 					 
}
//RTC WAKE UP中断服务函数
void RTC_WKUP_IRQHandler(void)
{
       
	if(RTC_GetFlagStatus(RTC_FLAG_WUTF)==SET)//WK_UP中断?
	{
    
		RTC_ClearFlag(RTC_FLAG_WUTF);	//清除中断标志
	}   
	EXTI_ClearITPendingBit(EXTI_Line22);//清除中断线22的中断标志 						
}

4.2 ADC具体配置代码(温度传感器)

//初始化ADC
//开启温度传感器通道																   
void  Adc_Init(void)
{
       
     GPIO_InitTypeDef  GPIO_InitStructure;
	 ADC_CommonInitTypeDef ADC_CommonInitStructure;
	 ADC_InitTypeDef       ADC_InitStructure;
    
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//使能ADC1时钟

    //先初始化IO口
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;// 上拉
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化  
	
RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);	//ADC1复位
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE);	//复位结束	 
    
ADC_TempSensorVrefintCmd(ENABLE);//使能内部温度传感器
    ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //DMA失能
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; //ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36Mhz  
ADC_CommonInit(&ADC_CommonInitStructure);
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12位模式
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描模式	
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止触发检测,用软件触发
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐	
    ADC_InitStructure.ADC_NbrOfConversion = 1;//1个转换在规则序列中 也就是只转换规则序列1 
    ADC_Init(ADC1, &ADC_InitStructure);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_480Cycles );	//ADC5,ADC通道,480个周期,提高采样时间可以提高精确度		
	ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_480Cycles );	//ADC16,ADC通道,480个周期,提高采样时间可以提高精确度		
	
爬虫Python学习是指学习如何使用Python编程语言来进行网络爬取和数据提取的过程。Python是一种简单易学且功能强大的编程语言,因此被广泛用于爬虫开发。爬虫是指通过编写程序自动抓取网页上的信息,可以用于数据采集、数据分析、网站监测等多个领域。 对于想要学习爬虫的新手来说,Python是一个很好的入门语言。Python的语法简洁易懂,而且有丰富的第三方库和工具,如BeautifulSoup、Scrapy等,可以帮助开发者更轻松地进行网页解析和数据提取。此外,Python还有很多优秀的教程和学习资源可供选择,可以帮助新手快速入门并掌握爬虫技能。 如果你对Python编程有一定的基础,那么学习爬虫并不难。你可以通过观看教学视频、阅读教程、参与在线课程等方式来学习。网络上有很多免费和付费的学习资源可供选择,你可以根据自己的需求和学习风格选择适合自己的学习材料。 总之,学习爬虫Python需要一定的编程基础,但并不难。通过选择合适的学习资源和不断实践,你可以逐步掌握爬虫的技能,并在实际项目中应用它们。 #### 引用[.reference_title] - *1* *3* [如何自学Python爬虫? 零基础入门教程](https://blog.csdn.net/zihong523/article/details/122001612)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [新手小白必看 Python爬虫学习路线全面指导](https://blog.csdn.net/weixin_67991858/article/details/128370135)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Conn_w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值