因項目需要RTC由原來的DS1302(這個芯片的代碼還蠻多的,就不掛了)。更改為了SD2405ALPI-G,看網上類似的資源較少,與諸君分享一下,有不足之處也希望諸君指正。
對於SD2405模塊的資料可參見https://wenku.baidu.com/view/cbebaea1b0717fd5360cdc13.html。
首先是IIC協議(資料也蠻多,但是掛一下代碼,這個是自己驗證過可以使用的,我也會在代碼后面大致寫一下為啥還有一些要注意的小小細節),
1 void IIC_For_Init(void) 2 { 3 GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE); 4 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); 5 6 GPIO_InitStructure.GPIO_Pin=IIC_SCL_PIN; 7 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; 8 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; 9 GPIO_Init(RCC_APB2Periph_GPIOB,&GPIO_InitStructure); 10 11 GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN; 12 GPIO_Init(RCC_APB2Periph_GPIOB,&GPIO_InitStructure); 13 14 IIC_SCL=1; 15 IIC_SDA=1; 16 } 17 18 19 void SDA_OUT_For(void) 20 { 21 GPIO_InitTypeDef GPIO_InitStructure; 22 23 GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN; 24 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; 25 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; 26 GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure); 27 } 28 29 30 void SDA_IN_For(void) 31 { 32 GPIO_InitTypeDef GPIO_InitStructure; 33 34 GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN; 35 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; 36 GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure); 37 } 38 39 40 void IIC_For_Start(void) 41 { 42 43 SDA_OUT_For(); 44 IIC_SDA=1; 45 IIC_SCL=1; 46 delay_us(5); 47 IIC_SDA=0;//START:when CLK is high,DATA change form high to low 48 delay_us(6); 49 IIC_SCL=0; 50 } 51 52 void IIC_For_Stop(void) 53 { 54 SDA_OUT_For(); 55 IIC_SCL=0; 56 IIC_SDA=0;//STOP:when CLK is high DATA change form low to high 57 IIC_SCL=1; 58 delay_us(6); 59 IIC_SDA=1; 60 delay_us(6); 61 } 62 63 u8 IIC_For_Wait_Ack(void) 64 { 65 u8 tempTime=0; 66 67 IIC_SDA=1; 68 delay_us(1); 69 SDA_IN_For(); 70 IIC_SCL=1; 71 delay_us(1); 72 while(READ_SDA) 73 { 74 tempTime++; 75 if(tempTime>250) 76 { 77 IIC_For_Stop(); 78 return 1; 79 } 80 } 81 IIC_SCL=0; 82 return 0; 83 } 84 85 void IIC_For_Ack(void) 86 { 87 IIC_SCL=0; 88 SDA_OUT_For(); 89 IIC_SDA=0; 90 delay_us(2); 91 IIC_SCL=1; 92 delay_us(5); 93 IIC_SCL=0; 94 } 95 96 97 void IIC_For_NAck(void) 98 { 99 IIC_SCL=0; 100 SDA_OUT_For(); 101 IIC_SDA=1; 102 delay_us(2); 103 IIC_SCL=1; 104 delay_us(5); 105 IIC_SCL=0; 106 } 107 108 109 void IIC_For_Send_Byte(u8 txd) 110 { 111 u8 t; 112 SDA_OUT_For(); 113 IIC_SCL=0; 114 for(t=0;t<8;t++) 115 { 116 if((txd&0x80)>0) //0x80 1000 0000 117 IIC_SDA=1; 118 else 119 IIC_SDA=0; 120 txd<<=1; 121 delay_us(2); 122 IIC_SCL=1; 123 delay_us(2); 124 IIC_SCL=0; 125 delay_us(2); 126 } 127 } 128 129 u8 IIC_For_Read_Byte(u8 ack) 130 { 131 u8 i,receive=0; 132 SDA_IN_For(); 133 for(i=0;i<8;i++ ) 134 { 135 IIC_SCL=0; 136 delay_us(2); 137 IIC_SCL=1; 138 receive<<=1; 139 if(READ_SDA)receive++; 140 delay_us(1); 141 } 142 if (!ack) 143 IIC_For_NAck(); 144 else 145 IIC_For_Ack(); 146 return receive; 147 }
需要注意的有幾點:
1、IIC_SDA及IIC_SCL,在這里我使用的是位帶操作,https://www.cnblogs.com/leo0621/p/9494290.html,這位博友講的超詳細;
2、關於第一行與第二行的代碼:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
當時使用了JTAG的管腳(PB3/JTDO、PB4/JNTRST),而JTAG與SWD在默認情況下是開啟的,需要關掉JTAG管腳並使其作為普通的IO口,這也是調試了半天才想到的一個問題,若不是使用JTAG,則只需要對RCC_APB2Periph_GPIOB進行使能即可,以免誤傷;
3、對於SDA_IN_For()和SDA_OUT_For(),首先此處的命名是為了避免重復(因為還有另一個IIC文件來進行AT24C02),初始化采用了分別設置的方法,OUT下為推挽輸出,在IN下為上拉輸入。在這里值得一提的是,如果在SDA對應的管腳有上拉電阻在,則可以在最開始的IO配置中,將SDA腳配置為浮空輸入,不需要再分別設置SDA_IN_For()和SDA_OUT_For()兩個函數。
對於SD2405ALPI-G的函數如下:
1 #include "sd2405_driver.h" 2 3 u8 Time_Register[]={ 4 SD2405_ADDR_YEAR, 5 SD2405_ADDR_MONTH, 6 SD2405_ADDR_DAY, 7 SD2405_ADDR_HOUR, 8 SD2405_ADDR_MIN, 9 SD2405_ADDR_SEC, 10 SD2405_ADDR_WEEK 11 }; 12 13 u8 Time_Init[]={ 14 0x19, //year 2019 15 0x05, //month 5 16 0x27, //day 27 17 0x12, //hour 12 18 0x30, //minute 30 19 0x59, //second 59 20 0x06 //week 6 21 }; 22 23 void SD2405_Init(void) 24 { 25 IIC_For_Init(); 26 } 27 28 void SD2405_WriteOneByte(u8 WriteAddr , u8 Data) 29 { 30 IIC_For_Start(); 31 32 IIC_For_Send_Byte(0x64); 33 IIC_For_Wait_Ack(); 34 35 IIC_For_Send_Byte(WriteAddr); 36 IIC_For_Wait_Ack(); 37 38 IIC_For_Send_Byte(Data); 39 IIC_For_Wait_Ack(); 40 41 IIC_For_Stop(); 42 43 delay_ms(10); 44 } 45 46 u8 SD2405_ReadOneByte(u8 ReadAddr) 47 { 48 u8 temp; 49 50 IIC_For_Start(); 51 52 IIC_For_Send_Byte(0x64); 53 IIC_For_Wait_Ack(); 54 55 IIC_For_Send_Byte(ReadAddr); 56 IIC_For_Wait_Ack(); 57 58 IIC_For_Start(); 59 60 IIC_For_Send_Byte(0x65); 61 IIC_For_Wait_Ack(); 62 63 temp = IIC_For_Read_Byte(0); 64 65 IIC_For_Stop(); 66 67 return temp; 68 } 69 70 71 void Write_On(void) 72 { 73 SD2405_WriteOneByte(SD2405_ADDR_CTR2,0x80); 74 SD2405_WriteOneByte(SD2405_ADDR_CTR1,0x84); 75 } 76 77 void Write_Off(void) 78 { 79 SD2405_WriteOneByte(SD2405_ADDR_CTR1,0x00); 80 SD2405_WriteOneByte(SD2405_ADDR_CTR2,0x52); 81 } 82 83 void SD2405_Time_Init(void) 84 { 85 u8 i = 0; 86 Write_On(); 87 for(i=0;i<7;i++){ 88 SD2405_WriteOneByte(Time_Register[i],Time_Init[i]); 89 } 90 Write_Off(); 91 } 92 93 void SD2405_Read_Time(void) 94 { 95 u8 i = 0; 96 for(i=0;i<7;i++){ 97 Time_Init[i]=SD2405_ReadOneByte(Time_Register[i]); 98 } 99 }
首先對於讀寫來說,0110001?,前7位為尋址字節,其中?表示可為1或0,當為0時為寫,1時為讀。當?為0時即為0x64,當?為1時為0x65;對於讀寫操作只需要符合IIC讀寫方式即可。需要注意的是,要進行Write_On和Write_Off的切換,即可參見說明書第8頁中的說明,對於寫允許的操作,先WRTC1為1再使WRTC2和WRTC3為1,故在Write_On中為0x80,0x84(應注意CTR1寄存器中有的是WRTC3位和WRTC2位,CTR2中有的是WRTC1位,兩個寄存器是沒按常理出牌的,不要寫顛倒);而寫禁止操作則需要先讓WRTC2和WRTC3為0再讓WRTC1為0,故分別為0x00和0x52。一定要先Write_On再寫再Write_Off。
在這里只是進行一個簡單的寫入並且不斷讀出並在OLED上進行顯示的過程(當然OLED顯示的代碼沒掛,主題還是SD2405嘛),對於報警、時間調整等更復雜的功能,還沒做但是也期待與諸君有更深入的討論。
