基於STM32的SD2405ALPI-G代碼


  因項目需要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嘛),對於報警、時間調整等更復雜的功能,還沒做但是也期待與諸君有更深入的討論。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM