基于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嘛),对于报警、时间调整等更复杂的功能,还没做但是也期待与诸君有更深入的讨论。

上一篇:ODBC [Microsoft][ODBC Sql Server Driver][TCP/IP Sockets]SQL Server 不存在或访问被拒绝。


下一篇:解决问题后的记录 \[Microsoft\]\[ODBC 驱动程序管理器\] 未发现数据源名称并且未指定默认驱动程序