欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136
標題:
STM8L的RTC詳解及源程序
[打印本頁]
作者:
51hei小林
時間:
2016-10-10 00:01
標題:
STM8L的RTC詳解及源程序
STM8L集成了RTC模塊,這個模塊除了具有時鐘鬧鈴功能外,還具有自動喚醒的功能.自動喚醒在低功耗模式中很有用,因為RTC使用的是LSE(外部32768Hz的時鐘),可以運行在低功耗模式下,可以使用此功能周期性的喚醒CPU,執行任務,而不需要CPU一直運行,這樣可以達到低功耗.
此公眾號已開啟留言功能,歡迎大家留言,評論
從上圖可以看出,RTC共有三個部分,第一部分是時鐘,第二部分是時鐘鬧鈴,第三部分是自動喚醒.本文對自動喚醒功能,不做介紹.
我們先看上圖的時鐘部分,RTC的時鐘選擇LSE,為32768Hz,RTCDIV[2:0]這三位我們設置為0,不分頻.然后進入到PRE_DIV[6:0]這個異步分頻器,這個7位的分頻器,默認值為0x7F,保持默認值.至此時鐘頻率為32768/(127+1)=256Hz.繼續往下走,遇到PREDIV_S[12:0]這個是十三位同步分頻器,此分頻器默認值為0xFF,同樣保持默認值,至此頻率為256/(255+1)=1Hz.提供給時鐘部分的頻率是1Hz,上圖中的Calendar部分,一秒鐘計數一次,更新一次時鐘寄存器,這么低頻率可以降低系統的功耗.
上圖是STM8L的內部時鐘寄存器,對這些寄存器進行寫操作時,需要先解鎖RTC寄存器的寫保護功能,讀操作無需解鎖.
上圖是,RTC時鐘功能的初始化配置流程.主要是配置年月日時分秒的初始值.
上圖是,RTC鬧鐘功能的初始化配置流程,這里主要是設置定時的時間.
要將RTC的寄存器中的時間,讀取出來顯示到液晶屏上,首先要判斷RSF位是否置位,置位說明RTC_TRx,RTC_DRx這些寄存器可以被讀取.讀取時,先讀TR1寄存器,此時其他寄存器中的數據被鎖存,直到RTC_DR3被讀取.
上圖是,本例程執行時的圖片,液晶屏1S更新一次數據,圖中顯示當前時間為21:46:30.同時右下角的藍燈會以2Hz的頻率閃爍,在鬧鐘中斷中取反藍燈控制IO,所以會是2Hz閃爍.
/****************************************************************************************
*開發環境:IAR for stm8 v6.5.3
*硬件平臺:STM8L-DISCOVERY
*功能說明:使用STM8L-DISCOVERY液晶屏顯示時間
*作 者:茗風
****************************************************************************************/
#include"iostm8l152c6.h"
#include"stdint.h"
#include"stdbool.h"
bool bRTC_Update_Flag = false;//標志位
/* =========================================================================
LCD MAPPING
=========================================================================
A
_ ----------
COL |_| |\ |J /|
F| H | K |B
_ | \ | / |
COL |_| --G-- --M--
| /| \ |
E| Q | N |C
_ | / |P \|
DP |_| -----------
D
*/
#define a 0x01
#define b 0x02
#define c 0x04
#define d 0x08
#define e 0x10
#define f 0x20
#define g 0x40
#define m 0x80
const uint8_t LCD_Tab[10] = {
a + b + c + d + e + f, // Displays "0"
b + c, // Displays "1"
a + b + m + g + e + d, // Displays "2"
a + b + m + g + c + d, // Displays "3"
f + g + m + b + c, // Displays "4"
a + f + g + m + c +d, // Displays "5"
a + f + e + d + c + g + m , // Displays "6"
a + b + c, // Displays "7"
a + b + c + d + e + f + g + m, // Displays "8"
a + b + c + d + f + g + m // Displays "9"
};
/******************************************************************************************************
* 名 稱:void GPIO_Init(void)
* 功 能:初始化PC7為高速推挽輸出
* 入口參數:無
* 出口參數:無
* 說 明:
* 范 例:無
******************************************************************************************************/
void GPIO_Init(void)
{
PC_CR1_C17 =1;//推挽輸出
PC_CR2_C27 =1;//高速輸出
PC_DDR_DDR7 =1;//PC4輸出
// PC_ODR_ODR7 =0;//輸出低電平
}
/******************************************************************************************************
* 名 稱:void LCD_Config(void)
* 功 能:配置LCD
* 入口參數:無
* 出口參數:無
* 說 明:
* 范 例:無
******************************************************************************************************/
void LCD_Config(void)
{
//------打開LCD/RTC時鐘------
// CLK_PCKENR2_PCKEN22=1;//打開RTC時鐘,LCD刷新頻率與此時鐘有關
CLK_PCKENR2_PCKEN23=1;//打開LCD時鐘,讀寫LCD寄存器用到此時鐘
//---選擇LSE作為RTC時鐘---
// CLK_CRTCR_RTCSEL0=0;
// CLK_CRTCR_RTCSEL1=0;
// CLK_CRTCR_RTCSEL2=0;
// CLK_CRTCR_RTCSEL3=1;
/* 0000: No clock selected
0001: HSI clock used as RTC clock source
0010: LSI clock used as RTC clock source
0100: HSE clock used as RTC clock source
1000: LSE clock used as RTC clock sourc*/
//----設置RTC時鐘分頻值----
// CLK_CRTCR_RTCDIV0=0;
// CLK_CRTCR_RTCDIV1=0;
// CLK_CRTCR_RTCDIV2=0;
/*000: RTC clock source/1
001: RTC clock source /2
010: RTC clock source /4
011: RTC clock source /8
100: RTC clock source /16
101: RTC clock source /32
110: RTC clock source /64
111: RTC clock source /128*/
//----設置LCD預分頻值----
LCD_FRQ_PS0=0;// 2^PS[3:0]
LCD_FRQ_PS1=0;//分頻值為1
LCD_FRQ_PS2=0;
LCD_FRQ_PS3=0;
//----設置LCD分頻值----
LCD_FRQ_DIV0=1;//DIV[3:0]+16
LCD_FRQ_DIV1=1;//分頻值為15+16=31
LCD_FRQ_DIV2=1;
LCD_FRQ_DIV3=1;
//以上分頻值的設置,最為了得到適合的LCD的刷新頻率,如果增大分頻值,會導致
//LCD刷新頻率變低,會看到LCD顯示出現閃爍
//比如,我們將PS[3:0]設置為0011,會看到液晶閃爍
//----1/4 duty----
LCD_CR1_DUTY0=1;//1/4 duty
LCD_CR1_DUTY1=1;
/* Duty ratio selection
00: Static duty
01: 1/2 duty
10: 1/3 duty
11: 1/4 duty */
//----1/3 bias----
LCD_CR1_B2=0;//1/3 bias
/* 0: 1/3 bias
1: 1/2 bias */
//----內部電壓源----
LCD_CR2_VSEL=0;
//----打開引腳的SEG功能----
// LCD_PM0=0xFF;//頭文件這個地方定義錯誤,無法直接向LCD_PM0寫入數據
// LCD_PM1=0xFF;//PM0寄存器定義錯誤,導致PM1也無法直接寫入
// LCD_PM2=0xFF;//PM0寄存器定義錯誤,導致PM2也無法直接寫入
*((uint8_t *)0x5404)=0xFF;//直接向LCD_PM0寄存器的地址寫入數據
*((uint8_t *)0x5405)=0xFF;//直接向LCD_PM1寄存器的地址寫入數據
*((uint8_t *)0x5406)=0xFF;//直接向LCD_PM2寄存器的地址寫入數據
//----To set contrast to mean value----
LCD_CR2_CC0=0;//對比度
LCD_CR2_CC1=1;
LCD_CR2_CC2=0;
/* 000: VLCD0 2.6V
001: VLCD1 2.7V
010: VLCD2 2.8V
011: VLCD3 2.9V
100: VLCD4 3.0V
101: VLCD5 3.1V
110: VLCD6 3.2V
111: VLCD7 */
//----Dead time 0----
LCD_CR3_DEAD0=0;//no dead time
LCD_CR3_DEAD1=0;
LCD_CR3_DEAD2=0;
//----LCD_PulseOnDuration_1----
LCD_CR2_PON0=1;
LCD_CR2_PON1=0;
LCD_CR2_PON2=0;
/* 000: 0 CLKps pulses
001: 1 CLKps pulses
010: 2 CLKps pulses
011: 3 CLKps pulses
100: 4 CLKps pulses
101: 5 CLKps pulses
110: 6 CLKps pulses
111: 7 CLKps pulses */
//----Enable LCD peripheral----
LCD_CR3_LCDEN=1;
}
/******************************************************************************************************
* 名 稱:LCD_DisplayNum(uint8_t number)
* 功 能:控制段式液晶屏的數字顯示部分
* 入口參數:number:要顯示的數字
* 出口參數:無
* 說 明:根據數字的長度,判斷要顯示的長度,長度大于6位,只顯示后六位
* 范 例:無
******************************************************************************************************/
void LCD_DisplayNum(uint32_t number)
{
uint8_t cnts=0,tmp=0;
if(number<10)cnts=1;
else if(number<100)cnts=2;
else if(number<1000)cnts=3;
else if(number<10000)cnts=4;
else if(number<100000)cnts=5;
else if(number<(uint32_t) 1000000)cnts=6;
else cnts=6;
//判斷需要顯示數字的長度,確定在LCD屏上需要的位數
switch(cnts)
{
case 6:
tmp = LCD_Tab[number%1000000/100000];
((tmp&m)==0)?(LCD_RAM0&=~0x02):(LCD_RAM0 |=0x02) ;
((tmp&e)==0)?(LCD_RAM0&=~0x01):(LCD_RAM0 |=0x01) ;
((tmp&g)==0)?(LCD_RAM2&=~0x80):(LCD_RAM2 |=0x80) ;
((tmp&b)==0)?(LCD_RAM2&=~0x40):(LCD_RAM2 |=0x40) ;
((tmp&f)==0)?(LCD_RAM6&=~0x08):(LCD_RAM6 |=0x08) ;
((tmp&a)==0)?(LCD_RAM6&=~0x04):(LCD_RAM6 |=0x04) ;
((tmp&c)==0)?(LCD_RAM3&=~0x20):(LCD_RAM3 |=0x20) ;
((tmp&d)==0)?(LCD_RAM3&=~0x10):(LCD_RAM3 |=0x10) ;
case 5:
tmp = LCD_Tab[number%100000/10000];
((tmp&m)==0)?(LCD_RAM0&=~0x08):(LCD_RAM0 |=0x08) ;
((tmp&e)==0)?(LCD_RAM0&=~0x04):(LCD_RAM0 |=0x04) ;
((tmp&g)==0)?(LCD_RAM2&=~0x20):(LCD_RAM2 |=0x20) ;
((tmp&b)==0)?(LCD_RAM2&=~0x10):(LCD_RAM2 |=0x10) ;
((tmp&f)==0)?(LCD_RAM6&=~0x02):(LCD_RAM6 |=0x02) ;
((tmp&a)==0)?(LCD_RAM6&=~0x01):(LCD_RAM6 |=0x01) ;
((tmp&c)==0)?(LCD_RAM3&=~0x80):(LCD_RAM3 |=0x80) ;
((tmp&d)==0)?(LCD_RAM3&=~0x40):(LCD_RAM3 |=0x40) ;
case 4:
tmp = LCD_Tab[number%10000/1000];
((tmp&m)==0)?(LCD_RAM0&=~0x20):(LCD_RAM0 |=0x20) ;
((tmp&e)==0)?(LCD_RAM0&=~0x10):(LCD_RAM0 |=0x10) ;
((tmp&g)==0)?(LCD_RAM2&=~0x08):(LCD_RAM2 |=0x08) ;
((tmp&b)==0)?(LCD_RAM2&=~0x04):(LCD_RAM2 |=0x04) ;
((tmp&f)==0)?(LCD_RAM5&=~0x80):(LCD_RAM5 |=0x80) ;
((tmp&a)==0)?(LCD_RAM5&=~0x40):(LCD_RAM5 |=0x40) ;
((tmp&c)==0)?(LCD_RAM4&=~0x02):(LCD_RAM4 |=0x02) ;
((tmp&d)==0)?(LCD_RAM4&=~0x01):(LCD_RAM4 |=0x01) ;
case 3:
tmp = LCD_Tab[number%1000/100];
((tmp&m)==0)?(LCD_RAM0&=~0x80):(LCD_RAM0 |=0x80) ;
((tmp&e)==0)?(LCD_RAM0&=~0x40):(LCD_RAM0 |=0x40) ;
((tmp&g)==0)?(LCD_RAM2&=~0x02):(LCD_RAM2 |=0x02) ;
((tmp&b)==0)?(LCD_RAM2&=~0x01):(LCD_RAM2 |=0x01) ;
((tmp&f)==0)?(LCD_RAM5&=~0x20):(LCD_RAM5 |=0x20) ;
((tmp&a)==0)?(LCD_RAM5&=~0x10):(LCD_RAM5 |=0x10) ;
((tmp&c)==0)?(LCD_RAM4&=~0x08):(LCD_RAM4 |=0x08) ;
((tmp&d)==0)?(LCD_RAM4&=~0x04):(LCD_RAM4 |=0x04) ;
case 2:
tmp = LCD_Tab[number%100/10];
((tmp&m)==0)?(LCD_RAM1&=~0x02):(LCD_RAM1 |=0x02) ;
((tmp&e)==0)?(LCD_RAM1&=~0x01):(LCD_RAM1 |=0x01) ;
((tmp&g)==0)?(LCD_RAM1&=~0x80):(LCD_RAM1 |=0x80) ;
((tmp&b)==0)?(LCD_RAM1&=~0x40):(LCD_RAM1 |=0x40) ;
((tmp&f)==0)?(LCD_RAM5&=~0x08):(LCD_RAM5 |=0x08) ;
((tmp&a)==0)?(LCD_RAM5&=~0x04):(LCD_RAM5 |=0x04) ;
((tmp&c)==0)?(LCD_RAM4&=~0x20):(LCD_RAM4 |=0x20) ;
((tmp&d)==0)?(LCD_RAM4&=~0x10):(LCD_RAM4 |=0x10) ;
case 1:
tmp = LCD_Tab[number%10];
((tmp&m)==0)?(LCD_RAM1&=~0x08):(LCD_RAM1 |=0x08) ;
((tmp&e)==0)?(LCD_RAM1&=~0x04):(LCD_RAM1 |=0x04) ;
((tmp&g)==0)?(LCD_RAM1&=~0x20):(LCD_RAM1 |=0x20) ;
((tmp&b)==0)?(LCD_RAM1&=~0x10):(LCD_RAM1 |=0x10) ;
((tmp&f)==0)?(LCD_RAM5&=~0x02):(LCD_RAM5 |=0x02) ;
((tmp&a)==0)?(LCD_RAM5&=~0x01):(LCD_RAM5 |=0x01) ;
((tmp&c)==0)?(LCD_RAM4&=~0x80):(LCD_RAM4 |=0x80) ;
((tmp&d)==0)?(LCD_RAM4&=~0x40):(LCD_RAM4 |=0x40) ;
break;
default:break;
}
}
/******************************************************************************************************
* 名 稱:LCD_DisplayTime(uint8_t number)
* 功 能:調用LCD數字顯示程序,顯示RTC的時分秒
* 入口參數:無
* 出口參數:1:運行出錯,退出 0:函數執行完成
* 說 明:此函數,首先將RTC的時分秒寄存器按照順序,組合成一個數,然后調用上面的函數進行顯示
* 范 例:無
******************************************************************************************************/
uint8_t LCD_DisplayTime(void)
{
uint32_t tmp=0;
if(RTC_ISR1_RSF==0)return 1;//判斷RTC時分秒寄存器的值有沒有被拷貝到TR影子寄存器,沒有就退出
tmp += (uint32_t)RTC_TR1_SU;
tmp += (uint32_t)RTC_TR1_ST*10;
tmp += (uint32_t)RTC_TR2_MNU*100;
tmp += (uint32_t)RTC_TR2_MNT*1000;
tmp += (uint32_t)RTC_TR3_HU*10000;
tmp += (uint32_t)RTC_TR3_HT*100000;
RTC_ISR1_RSF=0; //清零
LCD_DisplayNum(tmp);
return 0;
}
/******************************************************************************************************
* 名 稱:void RTC_Config(void)
* 功 能:重新設置RTC的時分秒年月日,同時鬧鈴設置為一秒進入一次中斷
* 入口參數:無
* 出口參數:無
* 說 明:
* 范 例:無
******************************************************************************************************/
void RTC_Config(void)
{
//------打開LCD/RTC時鐘------
CLK_PCKENR2_PCKEN22=1;
//---選擇LSE作為RTC時鐘---
CLK_CRTCR_RTCSEL0=0;
CLK_CRTCR_RTCSEL1=0;
CLK_CRTCR_RTCSEL2=0;
CLK_CRTCR_RTCSEL3=1;
/* 0000: No clock selected
0001: HSI clock used as RTC clock source
0010: LSI clock used as RTC clock source
0100: HSE clock used as RTC clock source
1000: LSE clock used as RTC clock sourc*/
//----設置RTC時鐘分頻值----
CLK_CRTCR_RTCDIV0=0;
CLK_CRTCR_RTCDIV1=0;
CLK_CRTCR_RTCDIV2=0;
/*000: RTC clock source/1
001: RTC clock source /2
010: RTC clock source /4
011: RTC clock source /8
100: RTC clock source /16
101: RTC clock source /32
110: RTC clock source /64
111: RTC clock source /128*/
//關閉RTC寄存器的寫保護功能
RTC_WPR=0xCA;
RTC_WPR=0x53;
RTC_ISR1_INIT=1;//進入初始化模式,計數器停止工作
while(!RTC_ISR1_INITF);//等待同步完成
//初始化時間和日期
RTC_TR1_ST=0;//second tens
RTC_TR1_SU=0;//second units
RTC_TR2_MNT=4;//minute tens
RTC_TR2_MNU=7;//minute units
RTC_TR3_PM=0;//AM/PM
RTC_TR3_HT=2;//hour tens
RTC_TR3_HU=1;//hour units
RTC_DR1_DT=2;//date tens
RTC_DR1_DU=6;//date units
RTC_DR2_WDU=1;//week day units
RTC_DR2_MT=0;//month tens
RTC_DR2_MU=9;//month units
RTC_DR3_YT=1;//year tens
RTC_DR3_YU=6;//year units
RTC_CR1_FMT=0;//24小時模式
// RTC_APRER=0x7F;//保持默認值0x7F
// RTC_SPRERL=0x00;
// RTC_SPRERL=0xFF;//保持默認值0xFF
//以上兩個RTC時鐘分頻值保持默認
//最終提供給日歷模塊的時鐘為 32768Hz/( (127+1)*(255+1) ) =1Hz
RTC_ISR1_INIT=0;//退出初始化模式
//設置鬧鐘
RTC_CR2_ALRAE=0;//disable the alarm
while(!RTC_ISR1_ALRAWF);//
//設置鬧鐘時間
//屏蔽了所有時間,導致鬧鐘1秒中執行一次,進入一次鬧鐘中斷
RTC_ALRMAR1_MSK1=1;//屏蔽秒定時
RTC_ALRMAR1_ALST=2;//second tens
RTC_ALRMAR1_ALSU=0;//second units
RTC_ALRMAR2_MSK2=1;//屏蔽分鐘定時
RTC_ALRMAR2_ALMNT=0;//minute tens
RTC_ALRMAR2_ALMNU=0;//minute units
RTC_ALRMAR3_MSK3=1;//屏蔽小時定時
RTC_ALRMAR3_ALHT=0;//hour tens
RTC_ALRMAR3_ALHU=6;//hour units
RTC_ALRMAR3_PM=0;
RTC_ALRMAR4_MSK4=1;//屏蔽關閉天定時
RTC_ALRMAR4_ALDT=0;
RTC_ALRMAR4_ALDU=0;
RTC_ALRMAR4_WDSEL=0;
RTC_CR2_ALRAE=1;//使能鬧鈴功能
RTC_CR2_ALRAIE=1;//使能鬧鈴中斷
//programming the auto-wakeup timer
// RTC_CR2_WUTE=0;//disable the wakeup timer
// while(!RTC_ISR1_WUTWF);
// RTC_WUTRH=0;//裝初值
// RTC_WUTRL=8;//
//配置自動喚醒分頻值
//RTC_CR1_WUCKSEL=0x03;//32768Hz/2=16384Hz
/* 000: RTCCLK/16 clock is selected
001: RTCCLK/8 clock is selected
010: RTCCLK/4 clock is selected
011: RTCCLK/2 clock is selected */
// RTC_CR2_WUTE=0;//enable the tiemr again
// RTC_CR2_WUTIE=0;
RTC_WPR=0x55;//使能寫保護
RTC_WPR=0x55;
}
void main(void)
{
GPIO_Init();
LCD_Config();
RTC_Config();
asm("rim"); //enable interrupts
while(1)
{
if(bRTC_Update_Flag)
{
bRTC_Update_Flag=false;
LCD_DisplayTime();
}
asm("halt");//執行此條語句后,STM8L152C6進入低功耗模式,主時鐘關閉,但RTC仍然在運行
}
}
#pragma vector=RTC_ALARM_vector
__interrupt void RTC_ALARM_ISR(void)
{
PC_ODR_ODR7 ^=0x01;
bRTC_Update_Flag=true;
RTC_ISR2_ALRAF=0;
}
復制代碼
作者:
werjufour
時間:
2023-7-13 12:50
這里不用讀取DR3的值也能更新時間么?
作者:
werjufour
時間:
2023-7-13 15:14
大佬,還有個問題,你這個鬧鐘中斷,鬧鐘時間是這么設置的。有點懵
歡迎光臨 (http://www.raoushi.com/bbs/)
Powered by Discuz! X3.1