上海天局信息技术有限责任公司

网站首页 > 天局论坛 > Drivers

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

2018-11-01 13:01:04 上海天局信息技术有限责任公司 已读

驱动之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.c5 * Description: I2C Drive operation center6 * Created: 2016.10.13.7 * Author: Yu Weifeng8 * 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 DateVersion Author Modification 46 * ----------------------------------------------- 47 * 2016/10/13 V1.0.0 Yu WeifengCreated 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 DateVersion Author Modification 61 * ----------------------------------------------- 62 * 2016/10/13 V1.0.0 Yu WeifengCreated 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/False100 * Modify DateVersion Author Modification101 * -----------------------------------------------102 * 2016/10/13 V1.0.0 Yu WeifengCreated103 ******************************************************************************/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);    //对应引脚PB110         ret=TRUE;111 }112     else if(GPIO_PIN_RESET==i_ucSetValue)113 {114         HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);    //对应引脚PB115         ret=TRUE;116 }117     else118 {119         ret=FALSE;120         DebugPrintf(ERR"I2C_SDA_SET format err\r\n");121 }122     return ret;123 }124 /*****************************************************************************125 -Fuction: I2C_SDA_READ126 -Description: I2C_SDA_READ127 -Input: 
128 -Output : 
129 -Return : 
130 * Modify DateVersion Author Modification131 * -----------------------------------------------132 * 2016/10/13 V1.0.0 Yu WeifengCreated133 ******************************************************************************/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_SET142 -Description: I2C_SCL_SET143 -Input: 
144 -Output : 
145 -Return : True/False146 * Modify DateVersion Author Modification147 * -----------------------------------------------148 * 2016/10/13 V1.0.0 Yu WeifengCreated149 ******************************************************************************/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);    //对应引脚PB156         ret=TRUE;157 }158     else if(GPIO_PIN_RESET==i_ucSetValue)159 {160         HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);    //对应引脚PB161         ret=TRUE;162 }163     else164 {165         ret=FALSE;166         DebugPrintf(ERR"I2C_SCL_SET format err\r\n");167 }168     return ret;169 }170 171 /*****************************************************************************172 -Fuction: I2C_DevConfig173 -Description: I2C_DevConfig174 -Input: 
175 -Output : 
176 -Return : 
177 * Modify DateVersion Author Modification178 * -----------------------------------------------179 * 2016/10/13 V1.0.0 Yu WeifengCreated180 ******************************************************************************/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_Start199 -Description: I2C_Start//产生IIC起始信号200 -Input: 
201 -Output : 
202 -Return : 
203 * Modify DateVersion Author Modification204 * -----------------------------------------------205 * 2016/09/23 V1.0.0 Yu WeifengCreated206 ******************************************************************************/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_Stop219 -Description: I2C_Stop//产生IIC起始信号220 -Input: 
221 -Output : 
222 -Return : 
223 * Modify DateVersion Author Modification224 * -----------------------------------------------225 * 2016/09/23 V1.0.0 Yu WeifengCreated226 ******************************************************************************/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 high232     DelayUs(4);233     I2C_SCL_SET(1); 
234     I2C_SDA_SET(1);//发送I2C总线结束信号235     DelayUs(4);
236 }237 /*****************************************************************************238 -Fuction: I2C_AckGenerate239 -Description: I2C_AckGenerate////产生ACK应答240 -Input: 
241 -Output : 
242 -Return : 
243 * Modify DateVersion Author Modification244 * -----------------------------------------------245 * 2016/10/13 V1.0.0 Yu WeifengCreated246 ******************************************************************************/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_AckGenerate259 -Description: I2C_AckGenerate//////不产生ACK应答260 -Input: 
261 -Output : 
262 -Return : 
263 * Modify DateVersion Author Modification264 * -----------------------------------------------265 * 2016/10/13 V1.0.0 Yu WeifengCreated266 ******************************************************************************/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_SendByte279 -Description: I2C_SendByte////280 //IIC发送一个字节281 //返回从机有无应答282 //1,有应答283 //0,无应答284 -Input: 
285 -Output : 
286 -Return : 
287 * Modify DateVersion Author Modification288 * -----------------------------------------------289 * 2016/10/13 V1.0.0 Yu WeifengCreated290 ******************************************************************************/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_OnDev309 -Description: I2C_OnDev310 //等待应答信号到来311 //返回值:0,接收应答失败312 //1,接收应答成功313 314 -Input: 
315 -Output : 
316 -Return : 
317 * Modify DateVersion Author Modification318 * -----------------------------------------------319 * 2016/09/23 V1.0.0 Yu WeifengCreated320 ******************************************************************************/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);//时钟输出0341     ret=TRUE;342     return ret;
343 }344 345 /*****************************************************************************346 -Fuction: I2C_ReadByte347 -Description: I2C_ReadByte////348 //读1个字节,ack=1时,发送ACK,ack=0,发送nACK 
349 -Input: 
350 -Output : 
351 -Return : 
352 * Modify DateVersion Author Modification353 * -----------------------------------------------354 * 2016/10/13 V1.0.0 Yu WeifengCreated355 ******************************************************************************/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();//发送nACK373     else374         I2C_AckGenerate(); //发送ACK 375     return ucReceive;376 }
复制代码

 


Powered by MetInfo 5.3.17 ©2008-2021 www.metinfo.cn