|
这两天闲暇没事,用STM32写了个校时时钟的小程序。基本功能:手动校时,usb校时(可设定闹钟),掉电保存数据。自己配套了个校时上位机,如图:截取电脑实时时间,并设定闹钟时间,再由串口通讯传给STM32.

使用到的STM32资源:定时器2作数码管显示实时扫描,USART1用来校时,PWR,BKP,作掉电数据保存,RTC秒中断作为时钟时基。
中断优先级概述:1级优先:串口中断 2级优先:秒中断 3级优先:定时器2 PS:波特率默认115200
以下是代码:
——————————————————————————
/*WRITER:YQ
#include "stm32f10x.h"
#define PORTA GPIOA->ODR //定义PORTA指向GPIOA的数据寄存器
#define PORTD GPIOD->ODR //定义PORTC指向GPIOC的数据寄存器
#define PORTC GPIOC->ODR
#define key1 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2) //定义按键 key1 切换键
#define key2 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3) // key2 退出键
#define key3 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4) // key3 确定键
#define key4 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_5) // key4 闹钟键
const u8 table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
u8 Mode,nude;
int wan,wan1,qian,bai,shi,ge,time,i,butter,buzzer;
USART_InitTypeDef USART_InitStructure;
uint8_t TxBuf[13];
uint8_t RxBuf[13];
uint8_t num1;
int newtime,Alarm;
/**********************************************************************
* 名 称:GPIO_Configuration()
* 功 能:配置输入输出
* 入口参数:
* 出口参数:
-----------------------------------------------------------------------
* 说明:使用库函数,配置IO口
***********************************************************************/
void GPIO_Configuration()
{
GPIO_InitTypeDef GPIO_InitStructure;
SystemInit();
RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1 |RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD |
RCC_APB2Periph_GPIOE|RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //D1 D2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10; //D3,D4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //USART1 TX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); //A端口
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //USART1 RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //复用开漏输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //A端口
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7; //D1 D2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_2 | GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(GPIOE,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE, &GPIO_InitStructure);
}
void RTC_Configuration() //RTC初始化
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP|RCC_APB1Periph_PWR,ENABLE); //开备份寄存器和电源管理时钟
BKP_DeInit(); //备份寄存器缺省值填入
PWR_BackupAccessCmd(ENABLE); //使能RTC和备份寄存器的访问
RCC_LSEConfig(RCC_LSE_ON); //使能LSE晶振
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET);//等待LSE晶振就绪
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //把LSE晶振作为RTC的时钟源
RCC_RTCCLKCmd(ENABLE); //使能RTC时钟
RTC_WaitForSynchro();
RTC_WaitForLastTask(); //等待最近一次写操作完成
RTC_ITConfig(RTC_IT_SEC,ENABLE);//RTC秒中断使能
RTC_WaitForLastTask();
RTC_SetCounter(newtime); //更新时钟
RTC_WaitForLastTask(); //等待最近一次写操作完成
RTC_SetPrescaler(32767); //
RTC_WaitForLastTask();
RTC_SetAlarm(Alarm);
RTC_WaitForLastTask();
}
void RTC_Configuration1() //RTC初始化
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP,ENABLE);
PWR_BackupAccessCmd(ENABLE);
RCC_LSEConfig(RCC_LSE_ON);
RCC_GetFlagStatus(RCC_FLAG_LSIRDY);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC_ITConfig(RTC_IT_SEC,ENABLE);
RTC_WaitForLastTask();
RTC_SetPrescaler(32767);
RTC_WaitForLastTask();
RTC_SetAlarm(3600);
RTC_WaitForLastTask();
RTC_ITConfig(RTC_IT_ALR,ENABLE);
RTC_WaitForLastTask();
}
void TIM2_Configuration() //定时器初始化
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); // 使能定时器时钟
TIM_TimeBaseStructure.TIM_Period = 9; // 自动重载值
TIM_TimeBaseStructure.TIM_Prescaler = 7199; // 时钟预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //采样分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInit(TIM2, & TIM_TimeBaseStructure); //
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //使能定时器2中断
TIM_Cmd(TIM2,ENABLE); //使能定时器2这个外设
}
void USART_Configuration()
{
USART_InitStructure.USART_BaudRate = 115200;
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;
/* Configure USART1 */
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1, ENABLE);
}
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3); // 抢占式优先级别
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//指定中断源
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;// 指定响应优先级别1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3); // 抢占式优先级别
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;//指定中断源
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;// 指定响应优先级别1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;// 指定响应优先级别1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void Delay(__IO uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
void GPIOYB(unsigned int t)
{
unsigned int c;
for(c=0;c<t;c++)
{
GPIO_SetBits(GPIOE, GPIO_Pin_0);//
Delay(0x1AFF);
GPIO_ResetBits(GPIOE, GPIO_Pin_0);
Delay(0x1AFF);
}
}
/**********************************************************************
* 名 称:main()
* 功 能:主函数
* 入口参数:
* 出口参数:
-----------------------------------------------------------------------
* 说明:
***********************************************************************/
int main (void)
{
GPIO_Configuration();
NVIC_Configuration();
TIM2_Configuration();
RTC_Configuration1();
USART_Configuration();
while(1)
{
if(key1==0)
{
while(!key1);
Mode=1; //模式切换,Mode=1为校时模式 Mode=0为正常模式
while(key2)
{
if(key1==0)
{
while(!key1);
butter++;
if(butter>3)
butter=0;
}
switch(butter)
{
case 0:
if(key3==0)
{
while(!key3);
bai++;
if(bai>9)
bai=0;
}
break;
case 1:
if(key3==0)
{
while(!key3);
qian++;
if(qian>5)
qian=0;
}
break;
case 2:
if(key3==0)
{
while(!key3);
wan++;
if(wan>9)
wan=0;
}
break;
case 3:
if(key3==0)
{
while(!key3);
wan1++;
if(wan1>2)
wan1=0;
}
break;
default: break;
}
}
newtime=ge+shi*10+(bai+qian*10)*60+(wan+wan1*10)*3600; //计算出重新设定的时间值
RCC_BackupResetCmd(ENABLE); //清除备份域的数据
RTC_Configuration(); //配置RTC
Mode=0;
}
if (BKP_ReadBackupRegister(BKP_DR1) != 0xf312) //检测特殊值,如果不是证明是第一次上电
{
RTC_Configuration(); //配置RTC
BKP_WriteBackupRegister(BKP_DR1, 0xf312); //写入特殊值,下次不再配置RTC
}
}
}
void TIM2_IRQHandler(void) //用定时器1ms进行数码管的动态扫描
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
{
TIM_ClearFlag(TIM2,TIM_IT_Update); //清定时器中断标志
if(Mode==0)
{
time=RTC_GetCounter();
ge=time%3600%60%10;
shi=time%3600%60/10;
bai=time%3600/60%10;
qian=time%3600/60/10;
wan=time/3600%10;
wan1=time/3600/10;
}
if(wan1==2&&wan==4)
{
wan1=0;
wan=0;
qian=0;
bai=0;
shi=0;
ge=0;
}
switch(i)
{
case 0: PORTD=0;PORTA=table[wan1];
PORTD|=(1<<7); break;
case 1: PORTD=0;PORTA=table[wan];
PORTD|=(1<<8); break;
case 2: PORTD=0;PORTA=table[qian];
PORTD|=(1<<10); break;
case 3: PORTD=0;PORTA=table[bai];
PORTD|=(1<<9); break;
default: break;
}
i++;
if(i==4)
i=0;
}
}
void RTC_IRQHandler(void)
{
if(RTC_GetITStatus(RTC_IT_SEC) != RESET)
{
PORTC^=(1<<7);
RTC_ClearITPendingBit(RTC_IT_SEC);
RTC_WaitForLastTask();
}
if(RTC_GetITStatus(RTC_IT_ALR) != RESET)
{
for(buzzer=0;buzzer<50;buzzer++)
{
GPIOYB(100);
Delay(0xfffff);
}
RTC_ClearITPendingBit(RTC_IT_ALR);
RTC_WaitForLastTask();
}
}
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
RxBuf[num1++]=USART_ReceiveData(USART1);
if(num1==12)
{
for(num1=0;num1<12;num1++)
TxBuf[num1]=RxBuf[num1]-48;
num1=0;
}
if(num1==0)
{
newtime=TxBuf[5]+TxBuf[4]*10+(TxBuf[3]+TxBuf[2]*10)*60+(TxBuf[1]+TxBuf[0]*10)*3600; //计算出重新设定的时间值
Alarm=TxBuf[11]+TxBuf[10]*10+(TxBuf[9]+TxBuf[8]*10)*60+(TxBuf[7]+TxBuf[6]*10)*3600;
RCC_BackupResetCmd(ENABLE); //清除备份域的数据
RTC_Configuration(); //配置RTC
}
}
}
|
|