首页 > 代码库 > 驱动之SPI,UART,I2C的介绍与应用20170118

驱动之SPI,UART,I2C的介绍与应用20170118

这篇文章主要介绍基本的驱动也是用的最多的协议类驱动中的SPI,I2C和UART。首先从最简单的UART也就是串口讲起:

1.UART

         UART由两根线也就是TX,RX以及波特率产生器组成,操作比较简单,配置好后,就可以发送接收数据了,注意有的MCU需要接收数据时清除某些标记。如:

 技术分享

2.SPI

         SPI一般有三根线组成即CLK,MOSI,MISO,数据输入和输出是单独的一根线。一般的操作都是先发控制指令,再发地址,接着才是数据。例:

 技术分享

3.I2C

         I2C一般由两根线组成,即SDA,SCL,一根时钟线,一根数据线。关于I2C相关的开始信号,响应信号,停止信号时序见后面附录图片,这些信号一般都是通用封装好的,封装函数见附件(IO口模拟I2C)。

         下面重点介绍I2C的使用操作,一般通信步骤是开始信号,从机地址+读或写标记,等待回应,发送数据,等待回应(接收数据,发送回应(最后一次接收则不发回应)),停止信号,代码示例:

 技术分享

 技术分享

 技术分享

最后,再总结与强调一下

SPI、I2C、UART三种串行总线协议的区别:

1,字面意思上:

SPI(Serial Peripheral Interface:串行外设接口); 
I2C(INTER IC BUS) 
UART(Universal Asynchronous Receiver Transmitter:通用异步收发器)

2.各总线的信号线:

SPI总线由三条信号线组成:串行时钟(SCLK)、串行数据输出(SDO)、串行数据输入(SDI)。SPI总线可以实现 多个SPI设备互相连接。提供SPI串行时钟的SPI设备为SPI主机或主设备(Master),其他设备为SPI从机或从设备(Slave)。主从设备间可以实现全双工通信,当有多个从设备时,还可以增加一条从设备选择线。

I2C总线是双向、两线(SCL、SDA)、串行、多主控(multi-master)接口标准,具有总线仲裁机制,非常适合在器件之间进行近距离、非经常性的数据通信。在它的协议体系中,传输数据时都会带上目的设备的设备地址,因此可以实现设备组网。一根数据线上传输的一条报文包括:开始信号+设备地址+命令+数据+(ACK)+停止信号

UART总线是异步串口,因此一般比前两种同步串口的结构要复杂很多,一般由波特率产生器(产生的波特率等于传输波特率的16倍)、UART接收器、UART发送器组成,硬件上由两根线,一根用于发送,一根用于接收。

从第二点明显可以看出,SPI和UART可以实现全双工,但I2C不行;

总结:I2C线更少,但是技术上也更加麻烦些,因为I2C需要有双向IO的支持,而且使用上拉电阻,抗干扰能力较弱,一般用于同一板卡上芯片之间的通信,较少用于远距离通信。SPI实现要简单一些,UART需要固定的波特率,就是说两位数据的间隔要相等,而SPI则无所谓,因为它是有时钟的协议。

个人学习笔记附录:

 技术分享

 技术分享

 技术分享

 技术分享

 技术分享

 技术分享

 代码附件:

技术分享
  1 /*****************************************************************************
  2 * Copyright (C) 2014-2015 China Aerospace Telecommunications Ltd.  All rights reserved.
  3 ------------------------------------------------------------------------------
  4 * File Module        :     PT810 dev_I2C.c
  5 * Description        :     I2C Drive operation center
  6 * Created            :     2016.10.13.
  7 * Author            :     Yu Weifeng
  8 * Function List         :     
  9 * Last Modified     :     
 10 * History            :     
 11 ******************************************************************************/
 12 #include "stm32f4xx_hal.h"
 13 #include "CBasicTools.h"
 14 #include "Config.h"
 15 #include "dev_LightDistanceSensor.h"
 16 #include "core_CM4.h"
 17 #include "ucos_ii.h"
 18 
 19 static void I2C_DevConfig(void);
 20 static void I2C_Start();
 21 static void I2C_SendByte(u8 i_ucData);
 22 static u8 I2C_ReadByte(u8 i_ucAck);
 23 static u8 I2C_WaitAck();
 24 static void I2C_Stop();
 25 
 26 static T_I2C_DevManage g_tI2C_Dev ={
 27     .name="I2C_Dev",
 28     .DevConfig        =I2C_DevConfig,
 29     .DevI2C_Start        =I2C_Start,    
 30     .DevI2C_SendByte    =I2C_SendByte,
 31     .DevI2C_ReadByte    =I2C_ReadByte,
 32     .DevI2C_WaitAck    =I2C_WaitAck,
 33     .DevI2C_Stop        =I2C_Stop,
 34 };
 35 //IO方向设置
 36 #define SDA_IN()     {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;}    //PB9输入模式
 37 #define SDA_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;} //PB9输出模式
 38 
 39 /*****************************************************************************
 40 -Fuction        : I2C_DevInit
 41 -Description    : I2C_DevInit
 42 -Input            : 
 43 -Output         : 
 44 -Return         : True/False
 45 * Modify Date      Version         Author           Modification
 46 * -----------------------------------------------
 47 * 2016/10/13       V1.0.0         Yu Weifeng      Created
 48 ******************************************************************************/
 49 void I2C_DevInit()
 50 {
 51     RegisterI2C_Dev(&g_tI2C_Dev);
 52 }
 53 
 54 /*****************************************************************************
 55 -Fuction        : DelayUs
 56 -Description    : DelayUs
 57 -Input            : 
 58 -Output         : 
 59 -Return         : True/False
 60 * Modify Date      Version         Author           Modification
 61 * -----------------------------------------------
 62 * 2016/10/13       V1.0.0         Yu Weifeng      Created
 63 ******************************************************************************/
 64 static void DelayUs(u8 i_ucTime)
 65  {
 66     u16 wTime = 75*i_ucTime;
 67     while(wTime--);
 68 }
 69 //延时nus
 70 //nus:要延时的us数.    
 71 //nus:0~190887435(最大值即2^32/fac_us@fac_us=22.5)                                           
 72 void delay_us(u32 nus)
 73 {        
 74     u32 ticks;
 75     u32 told,tnow,tcnt=0;
 76     u32 reload=SysTick->LOAD;                //LOAD的值             
 77     ticks=nus*84;                         //系统时钟晶振为84M晶振 
 78     OSSchedLock();                    //阻止OS调度,防止打断us延时
 79     told=SysTick->VAL;                        //刚进入时的计数器值
 80     while(1)
 81     {
 82         tnow=SysTick->VAL;    
 83         if(tnow!=told)
 84         {        
 85             if(tnow<told)tcnt+=told-tnow;    //这里注意一下SYSTICK是一个递减的计数器就可以了.
 86             else tcnt+=reload-tnow+told;        
 87             told=tnow;
 88             if(tcnt>=ticks)break;            //时间超过/等于要延迟的时间,则退出.
 89         }  
 90     };
 91     OSSchedUnlock();                    //恢复OS调度                                                
 92 }
 93 
 94 /*****************************************************************************
 95 -Fuction        : I2C_SDA_SET
 96 -Description    : I2C_SDA_SET
 97 -Input            : 
 98 -Output         : 
 99 -Return         : True/False
100 * Modify Date      Version         Author           Modification
101 * -----------------------------------------------
102 * 2016/10/13       V1.0.0         Yu Weifeng      Created
103 ******************************************************************************/
104 static u8 I2C_SDA_SET(u8 i_ucSetValue)
105 {
106     u8 ret=FALSE;
107     if(GPIO_PIN_SET==i_ucSetValue)
108     {
109         HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);    //对应引脚PB
110         ret=TRUE;
111     }
112     else if(GPIO_PIN_RESET==i_ucSetValue)
113     {
114         HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);    //对应引脚PB        
115         ret=TRUE;
116     }
117     else
118     {
119         ret=FALSE;
120         DebugPrintf(ERR"I2C_SDA_SET format err\r\n");
121     }
122     return ret;
123 }
124 /*****************************************************************************
125 -Fuction        : I2C_SDA_READ
126 -Description    : I2C_SDA_READ
127 -Input            : 
128 -Output         : 
129 -Return         : 
130 * Modify Date      Version         Author           Modification
131 * -----------------------------------------------
132 * 2016/10/13       V1.0.0         Yu Weifeng      Created
133 ******************************************************************************/
134 static u8 I2C_SDA_READ()
135 {
136     u8 ret=0;
137     ret=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_9);
138     return ret;
139 }
140 /*****************************************************************************
141 -Fuction        : I2C_SCL_SET
142 -Description    : I2C_SCL_SET
143 -Input            : 
144 -Output         : 
145 -Return         : True/False
146 * Modify Date      Version         Author           Modification
147 * -----------------------------------------------
148 * 2016/10/13       V1.0.0         Yu Weifeng      Created
149 ******************************************************************************/
150 static u8 I2C_SCL_SET(u8 i_ucSetValue)
151 {
152     u8 ret=FALSE;
153     if(GPIO_PIN_SET==i_ucSetValue)
154     {
155         HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);    //对应引脚PB
156         ret=TRUE;
157     }
158     else if(GPIO_PIN_RESET==i_ucSetValue)
159     {
160         HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);    //对应引脚PB        
161         ret=TRUE;
162     }
163     else
164     {
165         ret=FALSE;
166         DebugPrintf(ERR"I2C_SCL_SET format err\r\n");
167     }
168     return ret;
169 }
170 
171 /*****************************************************************************
172 -Fuction        : I2C_DevConfig
173 -Description    : I2C_DevConfig
174 -Input            : 
175 -Output         : 
176 -Return         : 
177 * Modify Date      Version         Author           Modification
178 * -----------------------------------------------
179 * 2016/10/13       V1.0.0         Yu Weifeng      Created
180 ******************************************************************************/
181 static void I2C_DevConfig(void)
182 {
183     GPIO_InitTypeDef GPIO_Initure;
184     
185     __HAL_RCC_GPIOB_CLK_ENABLE();    //使能GPIOH时钟
186     
187     //PB8,9初始化设置
188     GPIO_Initure.Pin=GPIO_PIN_8|GPIO_PIN_9;
189     GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;    //推挽输出
190     GPIO_Initure.Pull=GPIO_PULLUP;            //上拉
191     GPIO_Initure.Speed=GPIO_SPEED_FAST;     //快速
192     HAL_GPIO_Init(GPIOB,&GPIO_Initure);
193     
194     I2C_SDA_SET(1);
195     I2C_SCL_SET(1);
196 }
197 /*****************************************************************************
198 -Fuction        : I2C_Start
199 -Description    : I2C_Start//产生IIC起始信号
200 -Input            : 
201 -Output         : 
202 -Return         : 
203 * Modify Date      Version         Author           Modification
204 * -----------------------------------------------
205 * 2016/09/23       V1.0.0         Yu Weifeng      Created
206 ******************************************************************************/
207 static void I2C_Start()
208 {
209     SDA_OUT();       //sda线输出
210     I2C_SDA_SET(1);
211     I2C_SCL_SET(1);
212     DelayUs(4);
213     I2C_SDA_SET(0);//START:when CLK is high,DATA change form high to low 
214     DelayUs(4);
215     I2C_SCL_SET(0);//钳住I2C总线,准备发送或接收数据 
216 }
217 /*****************************************************************************
218 -Fuction        : I2C_Stop
219 -Description    : I2C_Stop//产生IIC起始信号
220 -Input            : 
221 -Output         : 
222 -Return         : 
223 * Modify Date      Version         Author           Modification
224 * -----------------------------------------------
225 * 2016/09/23       V1.0.0         Yu Weifeng      Created
226 ******************************************************************************/
227 static void I2C_Stop()
228 {
229     SDA_OUT();//sda线输出
230     I2C_SCL_SET(0);
231     I2C_SDA_SET(0);//STOP:when CLK is high DATA change form low to high
232     DelayUs(4);
233     I2C_SCL_SET(1); 
234     I2C_SDA_SET(1);//发送I2C总线结束信号
235     DelayUs(4);                                
236 }
237 /*****************************************************************************
238 -Fuction        : I2C_AckGenerate
239 -Description    : I2C_AckGenerate////产生ACK应答
240 -Input            : 
241 -Output         : 
242 -Return         : 
243 * Modify Date      Version         Author           Modification
244 * -----------------------------------------------
245 * 2016/10/13       V1.0.0         Yu Weifeng      Created
246 ******************************************************************************/
247 static void I2C_AckGenerate()
248 {
249     I2C_SCL_SET(0);
250     SDA_OUT();
251     I2C_SDA_SET(0);
252     DelayUs(2);
253     I2C_SCL_SET(1);
254     DelayUs(2);
255     I2C_SCL_SET(0);
256 }
257 /*****************************************************************************
258 -Fuction        : I2C_AckGenerate
259 -Description    : I2C_AckGenerate//////不产生ACK应答
260 -Input            : 
261 -Output         : 
262 -Return         : 
263 * Modify Date      Version         Author           Modification
264 * -----------------------------------------------
265 * 2016/10/13       V1.0.0         Yu Weifeng      Created
266 ******************************************************************************/
267 static void I2C_AckNoGenerate()
268 {
269     I2C_SCL_SET(0);
270     SDA_OUT();
271     I2C_SDA_SET(1);
272     DelayUs(2);
273     I2C_SCL_SET(1);
274     DelayUs(2);
275     I2C_SCL_SET(0);
276 }
277 /*****************************************************************************
278 -Fuction        : I2C_SendByte
279 -Description    : I2C_SendByte////
280 //IIC发送一个字节
281 //返回从机有无应答
282 //1,有应答
283 //0,无应答
284 -Input            : 
285 -Output         : 
286 -Return         : 
287 * Modify Date      Version         Author           Modification
288 * -----------------------------------------------
289 * 2016/10/13       V1.0.0         Yu Weifeng      Created
290 ******************************************************************************/
291 static void I2C_SendByte(u8 i_ucData)
292 {
293     u8 c;   
294     SDA_OUT();         
295     I2C_SCL_SET(0);//拉低时钟开始数据传输
296     for(c=0;c<8;c++)
297     {              
298         I2C_SDA_SET((i_ucData&0x80)>>7);
299         i_ucData<<=1;       
300         DelayUs(2);   //对TEA5767这三个延时都是必须的
301         I2C_SCL_SET(1);
302         DelayUs(2); 
303         I2C_SCL_SET(0);    
304         DelayUs(2);
305     }
306 }
307 /*****************************************************************************
308 -Fuction        : I2C_OnDev
309 -Description    : I2C_OnDev
310 //等待应答信号到来
311 //返回值:0,接收应答失败
312 //        1,接收应答成功
313 
314 -Input            : 
315 -Output         : 
316 -Return         : 
317 * Modify Date      Version         Author           Modification
318 * -----------------------------------------------
319 * 2016/09/23       V1.0.0         Yu Weifeng      Created
320 ******************************************************************************/
321 static u8 I2C_WaitAck()
322 {
323     u8 ucErrTime=0;
324     u8 ret=FALSE;
325     SDA_IN();       //SDA设置为输入    
326     I2C_SDA_SET(1); 
327     DelayUs(1);       
328     I2C_SCL_SET(1); 
329     DelayUs(1);     
330     while(I2C_SDA_READ())
331     {
332         ucErrTime++;
333         if(ucErrTime>250)
334         {
335             I2C_Stop();
336             ret=FALSE;
337             return ret;  
338         }
339     }
340     I2C_SCL_SET(0);//时钟输出0    
341     ret=TRUE;
342     return ret;  
343 }
344 
345 /*****************************************************************************
346 -Fuction        : I2C_ReadByte
347 -Description    : I2C_ReadByte////
348 //读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
349 -Input            : 
350 -Output         : 
351 -Return         : 
352 * Modify Date      Version         Author           Modification
353 * -----------------------------------------------
354 * 2016/10/13       V1.0.0         Yu Weifeng      Created
355 ******************************************************************************/
356 static u8 I2C_ReadByte(u8 i_ucAck)
357 {
358     u8 c;
359     u8 ucReceive=0;
360     SDA_IN();//SDA设置为输入
361     for(c=0;c<8;c++ )
362     {
363         I2C_SCL_SET(0); 
364         DelayUs(2);
365         I2C_SCL_SET(1);
366         ucReceive<<=1;
367         if(I2C_SDA_READ())
368         ucReceive++;   
369         DelayUs(1); 
370     }                     
371     if (!i_ucAck)
372         I2C_AckNoGenerate();//发送nACK
373     else
374         I2C_AckGenerate(); //发送ACK   
375     return ucReceive;
376 }
View Code

 

驱动之SPI,UART,I2C的介绍与应用20170118