STM32F1系列的單片機本身自帶的RTC實時時鐘外設只是一個單純的32位計數(shù)器,沒有分立為年月日、小時、分鐘、秒等寄存器,使用起來不是很方便。這時可以考慮使用外部RTC芯片,比如使用SPI接口的雙向單數(shù)據(jù)線方式的DS1302實時時鐘芯片,或是FSMC接口的帶內(nèi)部電池的DS12885、DS12887、DS12887A、DS12C887和DS12C887A等芯片。
【接線】
DS12C887的VCC接+5V,GND接地。MOT懸空,AD0~1接PD14~15,AD2~3接PD0~1,AD4~7接PE7~10。RESET引腳接PA8(這個可以隨便接,與FSMC無關(guān)),DS接PD4,R/W接PD5,CS接PD7(這是100腳的單片機上唯一的FSMC片選引腳)。
PB7(NADV)必須通過一個反相器后才能接到AS,并且不可以用地址線A8~A25代替(DS12C887時序要求AS拉低后AD0~AD7上的地址信號才能撤銷,不可同時撤銷。如果AS接到AD8上,則地址信號AD8~AD0會被同時撤銷,不符合時序要求)。其接法如下圖所示:
特別注意74HC04的電源接的是3.3V,而DS12C887的電源接的是5V。
最好不要用一個三極管來代替74HC04反相器,因為三極管的切換速度太慢了,而且搞得不好功耗也會比74HC04高。例如,使用9012型的三極管,發(fā)射極接3.3V,基極通過一個10kΩ的電阻接PB7,集電極接PB12后再通過一個10kΩ的電阻接GND,運行下面的程序:
void test(void) { uint8_t i; for (i = 0; i < 3; i++) { printf("PB7=0, PB12=%d\n", GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12)); GPIO_WriteBit(GPIOB, GPIO_Pin_7, Bit_SET); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); printf("PB7=1, PB12=%d\n", GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12)); GPIO_WriteBit(GPIOB, GPIO_Pin_7, Bit_RESET); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); } }PB7為GPIO_Mode_Out_PP,PB12為GPIO_Mode_IN_FLOATING。輸出結(jié)果:
PB7=0, PB12=1 PB7=1, PB12=1 PB7=0, PB12=1 PB7=1, PB12=1 PB7=0, PB12=1 PB7=1, PB12=1可見輸出端PB12全為1,短時間內(nèi)根本無法反相。只有把NOP改成delay(1),降低速度后才能成功反相。若使用74HC04的話,即使程序中沒有NOP也能完成反相。
【程序1(寄存器版)】
#includeSTM32F103VE FSMC DS12C887 str=This is a string! A=0x00 B=0x82 C=0x00 D=0x00
D寄存器的最高位為0,看來DS12C887芯片里面的電池早就沒電了。。。。。
地址0x33~0x7f這一區(qū)域為自由SRAM,可以任意讀寫,不影響芯片功能。
以下為連線的實物圖。我用的是帶8MHz晶振的微雪STM32F103VET6核心板做的實驗。
左邊的芯片是DS12C887,右邊那個小的芯片是74HC04反相器。
【程序2(庫函數(shù)版)】
#include
【程序3:實際走時測試】
#include【頭文件DS12C887.h】
typedef __packed struct { __IO uint8_t SEC; __IO uint8_t SECALR; __IO uint8_t MIN; __IO uint8_t MINALR; __IO uint8_t HOUR; __IO uint8_t HOURALR; __IO uint8_t DAY; __IO uint8_t DATE; __IO uint8_t MONTH; __IO uint8_t YEAR; __IO uint8_t CR1; __IO uint8_t CR2; __IO uint8_t CR3; __IO uint8_t CR4; __IO uint8_t RAM1[36]; // 0x0e-0x31 __IO uint8_t CENTURY; __IO uint8_t RAM2[77]; // 0x33-0x7f } DS12C887_TypeDef; #define RTC2 ((DS12C887_TypeDef *)0x60000000) #define RTC2_CR1_UIP 0x80 #define RTC2_CR1_DV2 0x40 #define RTC2_CR1_DV1 0x20 #define RTC2_CR1_DV0 0x10 #define RTC2_CR1_RS3 0x08 #define RTC2_CR1_RS2 0x04 #define RTC2_CR1_RS1 0x02 #define RTC2_CR1_RS0 0x01 #define RTC2_CR2_SET 0x80 #define RTC2_CR2_PIE 0x40 #define RTC2_CR2_AIE 0x20 #define RTC2_CR2_UIE 0x10 #define RTC2_CR2_SQWE 0x08 #define RTC2_CR2_DM 0x04 #define RTC2_CR2_24_12 0x02 #define RTC2_CR2_DSE 0x01 #define RTC2_CR3_IRQF 0x80 #define RTC2_CR3_PF 0x40 #define RTC2_CR3_AF 0x20 #define RTC2_CR3_UF 0x10 #define RTC2_CR4_VRT 0x80 void DS12C887_Init(void);【程序3~5的運行結(jié)果】 DS12C887 RTC 2017-09-27! 21:06:41 Wed 2017-09-27! 21:06:42 Wed 2017-09-27! 21:06:43 Wed 2017-09-27! 21:06:44 Wed 2017-09-27! 21:06:45 Wed 2017-09-27! 21:06:46 Wed 2017-09-27! 21:06:47 Wed 2017-09-27! 21:06:48 Wed 2017-09-27! 21:06:49 Wed 2017-09-27! 21:06:50 Wed 2017-09-27! 21:06:51 Wed 2017-09-27! 21:06:52 Wed 2017-09-27! 21:06:53 Wed 2017-09-27! 21:06:54 Wed 2017-09-27! 21:06:55 Wed 2017-09-27! 21:06:56 Wed 2017-09-27! 21:06:57 Wed 2017-09-27! 21:06:58 Wed 2017-09-27! 21:06:59 Wed 2017-09-27! 21:07:00 Wed 2017-09-27! 21:07:01 Wed 2017-09-27! 21:07:02 Wed 2017-09-27! 21:07:03 Wed 2017-09-27! 21:07:04 Wed 2017-09-27! 21:07:05 Wed
【程序4:利用DS12C887的中斷輸出引腳IRQ喚醒處于STOP模式的STM32單片機,并輸出當前時間】
中斷引腳IRQ接到單片機的PB1引腳上。該程序的運行結(jié)果和上面的程序相同。
#include【程序5:外部事件喚醒STM32單片機并輸出當前時間】
DS12C887的中斷引腳連接到EXTI_Line1上,但配置為事件方式(Event)而不是中斷方式(Interrupt)喚醒STM32單片機。該程序的運行結(jié)果和上面的程序相同。
#include
評論