驅動之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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM