1. STM32 IIC
1.1 IIC简介
1.1.1 IIC物理层
半双工通信:允许双向通信,但同一时刻只能一端发送,不能同时进行;
主从模式:支持多设备通信
总线协议
同步通信
1.1.2 IIC协议层
(1)数据有效性规定
(2)起始和停止信号
(3)应答响应
(4)总线的寻址方式
(5)数据传输
1.2 AT24C02
2. 软件配置
3. 硬件设计
4. 软件设计
4.1 功能描述
首先检测 AT24C02 芯片是否存在,如果存在则输出 提示信息,然后通过按键 KEY_UP 和 KEY1 控制 AT24C02 数据读写,并输出写入和 读取的数据信息,最后让 DS0 指示灯闪烁提示系统正常运行。
4.2 软件实现
(1)使能所用 GPIO 端口时钟,初始化 GPIO
(2)使用软件模拟 I2C 通信时序,包含起始和停止信号、应答信号等
(3)编写 AT24C02 读写函数
(4)编写主函数
4.2.1 IIC.c
1.#include "IIC.h"
2.
3.
4.// ---------------------------1.使用IO口模拟IIC时序------------------------------
5./* ---------------------------------函数声明-------------------------------------
6.*函数名称:IIC_Iint
7.*输入参数:无
8.*返回参数:无
9.*功 能:初始化IIC
10.*作 者:lph
11.*日 期:2024/04/27
12.------------------------------------------------------------------------------ */
13.void IIC_Iint(void)
14.{
15. RCC_APB2PeriphClockCmd(IIC_SCL_PORT_RCC, ENABLE);
16. RCC_APB2PeriphClockCmd(IIC_SDA_PORT_RCC, ENABLE);
17.
18. GPIO_InitTypeDef GPIO_InitStructure;
19.
20. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
21. GPIO_InitStructure.GPIO_Pin = IIC_SCL_Pin;
22. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
23. GPIO_Init(IIC_SCL_PORT, &GPIO_InitStructure);
24.
25. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
26. GPIO_InitStructure.GPIO_Pin = IIC_SDA_Pin;
27. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
28. GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
29.
30. GPIO_SetBits(IIC_SCL_PORT, IIC_SCL_Pin); //默认SCL输出高电平
31. GPIO_SetBits(IIC_SDA_PORT, IIC_SDA_Pin); //默认SDA输出高电平
32.}
33.
34.
35./* ---------------------------------函数声明-------------------------------------
36.*函数名称:SDA_OUT
37.*输入参数:无
38.*返回参数:无
39.*功 能:SDA输出配置
40.*作 者:lph
41.*日 期:2024/04/27
42.------------------------------------------------------------------------------ */
43.void SDA_OUT(void)
44.{
45. GPIO_InitTypeDef GPIO_InitStructure;
46.
47. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
48. GPIO_InitStructure.GPIO_Pin = IIC_SDA_Pin;
49. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
50. GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
51.}
52.
53.
54./* ---------------------------------函数声明-------------------------------------
55.*函数名称:SDA_IN
56.*输入参数:无
57.*返回参数:无
58.*功 能:SDA输入配置
59.*作 者:lph
60.*日 期:2024/04/27
61.------------------------------------------------------------------------------ */
62.void SDA_IN(void)
63.{
64. GPIO_InitTypeDef GPIO_InitStructure;
65.
66. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
67. GPIO_InitStructure.GPIO_Pin = IIC_SDA_Pin;
68. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
69. GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
70.}
71.
72.
73./* ---------------------------------函数声明-------------------------------------
74.*函数名称:IIC_Start
75.*输入参数:无
76.*返回参数:无
77.*功 能:产生IIC起始信号
78.*作 者:lph
79.*日 期:2024/04/27
80.------------------------------------------------------------------------------ */
81.void IIC_Start(void)
82.{
83. SDA_OUT(); //SDA线输出
84. GPIO_SetBits(IIC_SCL_PORT,IIC_SCL_Pin);
85. GPIO_SetBits(IIC_SDA_PORT,IIC_SDA_Pin);
86. delay_us(5);
87. GPIO_ResetBits(IIC_SDA_PORT,IIC_SDA_Pin); //START:当SCL为高,SDA由高变低时
88. delay_us(6);
89. GPIO_ResetBits(IIC_SCL_PORT,IIC_SCL_Pin); //钳住I2C总线,准备发送或接收数据
90.}
91.
92.
93./* ---------------------------------函数声明-------------------------------------
94.*函数名称:IIC_Start
95.*输入参数:无
96.*返回参数:无
97.*功 能:产生IIC起始信号
98.*作 者:lph
99.*日 期:2024/04/27
100.------------------------------------------------------------------------------ */
101.void IIC_Stop(void)
102.{
103. SDA_OUT();
104. GPIO_ResetBits(IIC_SCL_PORT,IIC_SCL_Pin);
105. GPIO_ResetBits(IIC_SDA_PORT,IIC_SDA_Pin); //STOP:当SCL为高,SDA由低变高时
106. GPIO_SetBits(IIC_SCL_PORT,IIC_SCL_Pin);
107. delay_us(6);
108. GPIO_SetBits(IIC_SDA_PORT,IIC_SDA_Pin);
109. delay_us(6);
110.}
111.
112.
113./* ---------------------------------函数声明-------------------------------------
114.*函数名称:IIC_Wait_Ans
115.*输入参数:无
116.*返回参数:u8=1,接收应答失败
117. u8=0,接收应答成功
118.*功 能:等待应答信号到来
119.*作 者:lph
120.*日 期:2024/04/27
121.------------------------------------------------------------------------------ */
122.u8 IIC_Wait_Ans(void)
123.{
124. u8 tempTime=0;
125.
126. GPIO_SetBits(IIC_SDA_PORT,IIC_SDA_Pin);
127. delay_us(1);
128.
129. SDA_IN(); //SDA设置为输入
130. GPIO_SetBits(IIC_SCL_PORT,IIC_SCL_Pin);
131. delay_us(1);
132. while(READ_SDA)
133. {
134. tempTime++;
135. if(tempTime>250)
136. {
137. IIC_Stop();
138. return 1; //应答失败
139. }
140. }
141. GPIO_ResetBits(IIC_SCL_PORT,IIC_SCL_Pin);
142. return 0; //应答成功
143.}
144.
145.
146./* ---------------------------------函数声明-------------------------------------
147.*函数名称:IIC_Ans
148.*输入参数:无
149.*返回参数:无
150.*功 能:产生Ans应答信号
151.*作 者:lph
152.*日 期:2024/04/27
153.------------------------------------------------------------------------------ */
154.//应答信号
155.void IIC_Ans(void)
156.{
157. GPIO_ResetBits(IIC_SCL_PORT,IIC_SCL_Pin);
158. SDA_OUT();
159. GPIO_ResetBits(IIC_SDA_PORT,IIC_SDA_Pin);
160. delay_us(2);
161. GPIO_SetBits(IIC_SCL_PORT,IIC_SCL_Pin);
162. delay_us(5);
163. GPIO_ResetBits(IIC_SCL_PORT,IIC_SCL_Pin);
164.}
165.
166.
167./* ---------------------------------函数声明-------------------------------------
168.*函数名称:IIC_NoneAns
169.*输入参数:无
170.*返回参数:无
171.*功 能:产生NoneAns非应答信号
172.*作 者:lph
173.*日 期:2024/04/27
174.------------------------------------------------------------------------------ */
175.//非应答信号
176.void IIC_NoneAns(void)
177.{
178. GPIO_ResetBits(IIC_SCL_PORT,IIC_SCL_Pin);
179. SDA_OUT();
180. GPIO_SetBits(IIC_SDA_PORT,IIC_SDA_Pin);
181. delay_us(2);
182. GPIO_SetBits(IIC_SCL_PORT,IIC_SCL_Pin);
183. delay_us(5);
184. GPIO_ResetBits(IIC_SCL_PORT,IIC_SCL_Pin);
185.}
186.
187.
188./* ---------------------------------函数声明-------------------------------------
189.*函数名称:IIIC_SendByte
190.*输入参数:u8 txd:字节数据
191.*返回参数:无
192.*功 能:IIC发送一个字节的数据
193.*作 者:lph
194.*日 期:2024/04/27
195.------------------------------------------------------------------------------ */
196.void IIC_SendByte(u8 txd)
197.{
198. u8 i=0;
199.
200. SDA_OUT();
201. GPIO_ResetBits(IIC_SCL_PORT,IIC_SCL_Pin); //拉低时钟开始数据传输
202. for(i=0;i<8;i++)
203. {
204. if((txd&0x80)>0) //判断最高位是否为1
205. GPIO_SetBits(IIC_SDA_PORT,IIC_SDA_Pin);
206. else
207. GPIO_ResetBits(IIC_SDA_PORT,IIC_SDA_Pin);
208.
209. txd<<=1;
210. delay_us(2);
211. GPIO_SetBits(IIC_SCL_PORT,IIC_SCL_Pin);
212. delay_us(2);
213. GPIO_ResetBits(IIC_SCL_PORT,IIC_SCL_Pin);
214. }
215.}
216.
217.
218./* ---------------------------------函数声明-------------------------------------
219.*函数名称:IIC_ReadByte
220.*输入参数:u8 ans:是否应答?
221. ans=1,发送Ans
222. ans=0,发送NoneAns
223.*返回参数:无
224.*功 能:IIC读一个字节的数据
225.*作 者:lph
226.*日 期:2024/04/27
227.------------------------------------------------------------------------------ */
228.u8 IIC_ReadByte(u8 ans)
229.{
230. u8 i=0;
231. u8 receive=0;
232.
233. SDA_IN();
234.
235. for(i=0;i<8;i++)
236. {
237. GPIO_ResetBits(IIC_SCL_PORT,IIC_SCL_Pin);
238. delay_us(2);
239. GPIO_SetBits(IIC_SCL_PORT,IIC_SCL_Pin);
240. receive<<=1;
241. if(READ_SDA==1)
242. receive++;
243. delay_us(1);
244. }
245. if(!ans)
246. IIC_NoneAns();
247. else
248. IIC_Ans();
249. return receive;
250.}
4.2.2 IIC.h
1.#ifndef __IIC_H
2.#define __IIC_H
3.
4.#include "system.h"
5.#include "SysTick.h"
6.
7.#define IIC_SCL_PORT GPIOB
8.#define IIC_SCL_Pin GPIO_Pin_6
9.#define IIC_SCL_PORT_RCC RCC_APB2Periph_GPIOB
10.
11.#define IIC_SDA_PORT GPIOB
12.#define IIC_SDA_Pin GPIO_Pin_7
13.#define IIC_SDA_PORT_RCC RCC_APB2Periph_GPIOB
14.
15.// GPIO位带操作
16.#define IIC_SCL PBout(6)
17.#define IIC_SDA PBout(7)
18.#define READ_SDA PBin(7)
19.
20.void IIC_Iint(void);
21.void SDA_OUT(void);
22.void SDA_IN(void);
23.void IIC_Start(void);
24.void IIC_Stop(void);
25.void IIC_Ans(void);
26.void IIC_NoneAns(void);
27.void IIC_SendByte(u8 txd);
28.u8 IIC_ReadByte(u8 ans);
29.u8 IIC_Wait_Ans(void);
30.
31.#endif
4.2.3 AT24Cxx.c
1.#include "AT24Cxx.h"
2.
3.
4./* ---------------------------------函数声明-------------------------------------
5.*函数名称:AT24Cxx_Iint
6.*输入参数:无
7.*返回参数:无
8.*功 能:AT24CXX初始化
9.*作 者:lph
10.*日 期:2024/04/27
11.------------------------------------------------------------------------------ */
12.void AT24Cxx_Iint(void)
13.{
14. IIC_Iint();
15.}
16.
17.
18./* ---------------------------------函数声明-------------------------------------
19.*函数名称:AT24Cxx_WriteOneByte
20.*输入参数:WriteAddr:写入数据的目的地址
21. DataToWrite:要写入的数据
22.*返回参数:无
23.*功 能:在AT24CXX指定地址写入一个数据
24.*作 者:lph
25.*日 期:2024/04/27
26.------------------------------------------------------------------------------ */
27.void AT24Cxx_WriteOneByte(u8 WriteAdder,u8 data)
28.{
29. IIC_Start();
30.
31. if(EE_TYPE>AT24C16)
32. {
33. IIC_SendByte(0XA0); //发送写命令
34. IIC_Wait_Ans();
35. IIC_SendByte(WriteAdder>>8);//发送高地址
36. }
37. else
38. {
39. IIC_SendByte(0XA0+((WriteAdder/256)<<1)); //发送器件地址0XA0,写数据
40. }
41.
42. IIC_Wait_Ans();
43. IIC_SendByte(WriteAdder%256); //发送低地址
44. IIC_Wait_Ans();
45.
46. IIC_SendByte(data); //发送字节
47. IIC_Wait_Ans();
48.
49. IIC_Stop();//产生一个停止条件
50. delay_ms(10);
51.
52.}
53.
54.
55./* ---------------------------------函数声明-------------------------------------
56.*函数名称:AT24Cxx_ReadOneByte
57.*输入参数:ReadAddr:开始读数的地址
58.*返回参数:无
59.*功 能:在AT24CXX指定地址读出一个数据
60.*作 者:lph
61.*日 期:2024/04/27
62.------------------------------------------------------------------------------ */
63.u8 AT24Cxx_ReadOneByte(u8 ReadAdder)
64.{
65. u8 temp=0;
66.
67. IIC_Start();
68.
69. if(EE_TYPE>AT24C16)
70. {
71. IIC_SendByte(0XA0); //器件地址
72. IIC_Wait_Ans();
73. IIC_SendByte(ReadAdder>>8);//发送高地址
74. }
75. else
76. {
77. IIC_SendByte(0XA0+((ReadAdder/256)<<1)); //发送器件地址0XA0,写数据
78. }
79.
80. IIC_Wait_Ans();
81. IIC_SendByte(ReadAdder%256);
82. IIC_Wait_Ans();
83.
84. IIC_Start();
85. IIC_SendByte(0XA1); ////进入接收模式
86. IIC_Wait_Ans();
87.
88. temp=IIC_ReadByte(0);
89.
90. IIC_Stop();
91. return temp;
92.}
93.
94.
95./* ---------------------------------函数声明-------------------------------------
96.*函数名称:AT24Cxx_WriteLenByte
97.*输入参数:WriteAddr:写入数据的目的地址
98. DataToWrite:要写入的数据
99. Len:要写入数据的长度2,4
100.*返回参数:无
101.*功 能:在AT24CXX里面的指定地址开始写入长度为Len的数据,用于写入16bit或者32bit的数据
102.*作 者:lph
103.*日 期:2024/04/27
104.------------------------------------------------------------------------------ */
105.void AT24Cxx_WriteLenByte(u16 WriteAdder,u32 DataToWrite,u8 Len)
106.{
107. u8 t;
108. for(t=0;t<Len;t++)
109. {
110. AT24Cxx_WriteOneByte(WriteAdder+t,(DataToWrite>>(8*t))&0xff);
111. }
112.}
113.
114.
115./* ---------------------------------函数声明-------------------------------------
116.*函数名称:AT24Cxx_ReadLenByte
117.*输入参数:ReadAddr:开始读出的地址
118. Len:要读出数据的长度2,4
119.*返回参数:无
120.*功 能:在AT24CXX里面的指定地址开始读出长度为Len的数据,用于读出16bit或者32bit的数据
121.*作 者:lph
122.*日 期:2024/04/27
123.------------------------------------------------------------------------------ */
124.u32 AT24Cxx_ReadLenByte(u16 ReadAdder,u8 Len)
125.{
126. u8 t;
127. u32 temp=0;
128. for(t=0;t<Len;t++)
129. {
130. temp<<=8;
131. temp+=AT24Cxx_ReadOneByte(ReadAdder+Len-t-1);
132. }
133. return temp;
134.}
135.
136.
137./* ---------------------------------函数声明-------------------------------------
138.*函数名称:AT24Cxx_Check
139.*输入参数:无
140.*返回参数:u8=1,自检失败
141. u8=0,自检成功
142.*功 能:检查AT24CXX是否正常
143.*作 者:lph
144.*日 期:2024/04/27
145.------------------------------------------------------------------------------ */
146.u8 AT24Cxx_Check(void)
147.{
148. u8 temp=0;
149.
150. temp=AT24Cxx_ReadOneByte(255);
151. if(temp==0x36)
152. return 0;
153. else
154. {
155. AT24Cxx_WriteOneByte(255,0x36);
156. temp=AT24Cxx_ReadOneByte(255);
157. if(temp==0x36)
158. return 0;
159. }
160. return 1;
161.}
162.
163.
164./* ---------------------------------函数声明-------------------------------------
165.*函数名称:AT24Cxx_Read
166.*输入参数:ReadAddr:开始读出的地址 对24c02为0~255
167. pBuffer:数据数组首地址
168. NumToRead:要读出数据的个数
169.*返回参数:无
170.*功 能:在AT24CXX里面的指定地址开始读出指定个数的数据
171.*作 者:lph
172.*日 期:2024/04/27
173.------------------------------------------------------------------------------ */
174.void AT24Cxx_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
175.{
176. while(NumToRead)
177. {
178. *pBuffer++=AT24Cxx_ReadOneByte(ReadAddr++);
179. NumToRead--;
180. }
181.}
182.
183.
184./* ---------------------------------函数声明-------------------------------------
185.*函数名称:AT24Cxx_Write
186.*输入参数:WriteAddr:开始写入的地址 对24c02为0~255
187. pBuffer:数据数组首地址
188. NumToRead:要读出数据的个数
189.*返回参数:无
190.*功 能:在AT24CXX里面的指定地址开始写入指定个数的数据
191.*作 者:lph
192.*日 期:2024/04/27
193.------------------------------------------------------------------------------ */
194.void AT24Cxx_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
195.{
196. while(NumToWrite--)
197. {
198. AT24Cxx_WriteOneByte(WriteAddr,*pBuffer);
199. WriteAddr++;
200. pBuffer++;
201. }
202.}
203.
4.2.4 AT24Cxx.h
1.#ifndef __AT24Cxx_H
2.#define __AT24Cxx_H
3.
4.#include "system.h"
5.#include "IIC.h"
6.#include "SysTick.h"
7.
8.#define AT24C01 127
9.#define AT24C02 255
10.#define AT24C04 511
11.#define AT24C08 1023
12.#define AT24C16 2047
13.#define AT24C32 4095
14.#define AT24C64 8191
15.#define AT24C128 16383
16.#define AT24C256 32767
17.
18.//开发板使用的是24c02,所以定义EE_TYPE为AT24C02
19.#define EE_TYPE AT24C02
20.
21.void AT24Cxx_Iint(void);
22.void AT24Cxx_WriteOneByte(u8 WriteAdder,u8 data);
23.u8 AT24Cxx_ReadOneByte(u8 ReadAdder);
24.void AT24Cxx_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);
25.u32 AT24Cxx_ReadLenByte(u16 ReadAdder,u8 Len);
26.u8 AT24Cxx_Check(void);
27.void AT24Cxx_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);
28.void AT24Cxx_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);
29.
30.#endif
4.2.5 main.c
1./* Includes ------------------------------------------------------------------*/
2.#include "system.h"
3.#include "LED.h"
4.#include "SysTick.h"
5.#include "USART.h"
6.#include "IIC.h"
7.#include "AT24Cxx.h"
8.#include "KEY.h"
9.
10./* 主函数main() --------------------------------------------------------------*/
11.int main()
12.{
13. // 自定义变量
14. u8 i=0;
15. u8 key=0;
16. u8 input_data=0;
17. u8 output_data=0;
18. // 初始化
19. SysTick_Iint(72);
20. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组
21. LED_Init();
22. USART1_Iint(115200);
23. KEY_Iint();
24. AT24Cxx_Iint();
25.
26. while(AT24Cxx_Check())
27. {
28. printf("AT24Cxx检测不正常!\r\n");
29. delay_ms(500);
30. }
31. printf("AT24Cxx检测正常!\r\n");
32.
33.
34. while(1)
35. {
36. key=KEY_Scan(0);
37. if(key==KEY_UP_PRESS)
38. {
39. input_data++;
40. if(input_data>255)
41. input_data=255;
42. AT24Cxx_WriteOneByte(0,input_data);
43. printf("写入数据为:%d\r\n",input_data);
44. }
45. else if(key==KEY0_PRESS)
46. {
47. output_data=AT24Cxx_ReadOneByte(0);
48. printf("读取数据为:%d\r\n",output_data);
49. }
50.
51. i++;
52. if(i%20==0)
53. {
54. LED0=!LED0;
55. }
56.
57. delay_ms(10);
58. }
59.}