驱动之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/[email protected]_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 }

时间: 2024-10-22 14:26:52

驱动之SPI,UART,I2C的介绍与应用20170118的相关文章

嵌入式通讯开发 SPI,UART,I2C都有什么区别

SPI,UART,I2C都有什么区别,及其各自的特点 区别:SPI:高速同步串行口.3-4线接口,收发独立.可同步进行 UART:通用异步串行口.按照标准波特率完成双向通讯,速度慢 I2C:一种串行传输方式,三线制,网上可找到其通信协议和用法的 3根线实现数据双向传输 串行外围接口 Serial peripheral interface UART:通用异步收发器 UART是用于控制计算机与串行设备的芯片.有一点要注意的是,它提供了RS-232C数据终端设备接口,这样计算机就可以和调制解调器或其它

SPI,UART,I2C都有什么区别,及其各自的特点

区别: SPI:高速同步串行口.3-4线接口,收发独立.可同步进行 UART:通用异步串行口.按照标准波特率完成双向通讯,速度慢 I2C:一种串行传输方式,三线制,网上可找到其通信协议和用法的 3根线实现数据双向传输 串行外围接口 Serial peripheral interface UART:通用异步收发器 UART是用于控制计算机与串行设备的芯片.有一点要注意的是,它提供了RS-232C数据终端设备接口,这样计算机就可以和调制解调器或其它使用RS-232C接口的串行设备通信了.作为接口的一

常用协议(SPI, UART, I2C)

SPI: SPI是全双工的同步串行接口,数据速率可达几Mbps,在一般应用中有4根信号线:MOSI, MISO, SCK, SS. 根据时钟极性(CPOL)及相位(CPHA)不同可以组合成4种工作模式 CPOL=0:时钟空闲状态为低电平. CPOL=1:时钟空闲状态为高电平. CPHA=0:在时钟的第一个跳变沿进行数据采样. CPHA=1:在时钟的第二个跳变沿进行数据采样.

SPI、I2C、UART三种串行总线协议的区别和SPI接口介绍(转)

SPI.I2C.UART三种串行总线协议的区别 第一个区别当然是名字: SPI(Serial Peripheral Interface:串行外设接口); I2C(INTER IC BUS) UART(Universal Asynchronous Receiver Transmitter:通用异步收发器) 第二,区别在电气信号线上: SPI总线由三条信号线组成:串行时钟(SCLK).串行数据输出(SDO).串行数据输入(SDI).SPI总线可以实现多个SPI设备互相连接.提供SPI串行时钟的SPI

I2C总线介绍及AT24C02驱动编写 笔记

中断处理程序 { 清除中断 硬件自动清除 软件清除 } CPU芯片手册相关章节 -------- I2C CPU外接设备的方式 1)GPIO简洁的方式(按键,LED) 通过设置GPIO管脚的状态来完成通信(控制) gpccon gpcpud gpcdat 2)类似于内存的接口 (DDRAM norflash nand dm9000) 从硬件上看CPU和芯片 数据线 地址先  BANK 3)协议类接口 uart I2C AT24C02    EEPROM 3,如何解决CPU和设备通信的问题 I2C

SPI、I2C、UART、I2S、GPIO、SDIO、CAN

总线,总线,总要陷进里面.这世界上的信号都一样,但是总线却成千上万,让人头疼. 总的来说,总线有三种:内部总线.系统总线和外部总线.内部总线是微机内部各外围芯片与处理器之间的总线,用于芯片一级的互连:而系统总线是微机中各插件板与系统板之间的总线,用于插件板一级的互连:外部总线则是微机和外部设备之间的总线,微机作为一种设备,通过该总线和其他设备进行信息与数据交换,它用于设备一级的互连. 除了总线外,还有一些接口,它们是多种总线的集合体,或者说来者不拒. SPI (Serial Peripheral

Uart、SPI和I2C的区别

串口通信:UART.SPI.I2C区别[引用] 1.UART就是两线,一根发送一根接收,可以全双工通信,线数也比较少.数据是异步传输的,对双方的时序要求比较严格,通信速度也不是很快.在多机通信上面用的最多. 2.SPI接口和上面UART相比,多了一条同步时钟线,上面UART的缺点也就是它的优点了,对通信双方的时序要求不严格不同设备之间可以很容易结合,而且通信速度非常快.一般用在产品内部元件之间的高速数据通信上面,如大容量存储器等. 3.I2C接口也是两线接口,它是两根线之间通过复杂的逻辑关系传输

UART、SPI和I2C详解

做单片机开发时UART,SPI和I2C都是我们最经常使用到的硬件接口,我收集了相关的具体材料对这三种接口进行了详细的解释. UART UART是一种通用串行数据总线,用于异步通信.该总线双向通信,可以实现全双工传输和接收.在嵌入式设计中,UART用于主机与辅助设备通信,如汽车音响与外接AP之间的通信,与PC机通信包括与监控调试器和其它器件,如EEPROM通信. 将由计算机内部传送过来的并行数据转换为输出的串行数据流.将计算机外部来的串行数据转换为字节,供计算机内部并行数据的器件使用.在输出的串行

ADXL345经验总结,采用SPI和I2C总线操作

一. ADXL345简介 ADXL345是ADI公司推出的三轴(x,y,z)iMEMS数字加速度计(digital accelerometer),具有在16G下高分辨率(13Bit)测量能力,同时具备16Bit数字输出.ADXL345 适用于静态倾角测量以及动态加速度测量,高达4mg/LSB的灵敏度允许测量小于1度的倾角. 该传感器还具备单击 /双击探测,自由落体探测,并允许用户设置一个加速度阀值,当加速度值超过设定阀值后可以产生一个信号输出.所有这些功能都可以映射到2个中断上.内置的32级FI