日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

常用串行通信

發(fā)布時間:2025/7/14 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 常用串行通信 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

串行通信的速度較并行低,但是非常節(jié)省端口資源,所以是底層經(jīng)常接觸到的通信方式。

本文分為4部分

1、RS232串口通信

2、I2C通信

3、SPI通信

4、CAN通信

一、RS232串口通信

?

二、I2C通信

在I2C通信中,每個器件都有自己的固定地址,分為7位尋址和10位尋址模式,其中7位尋址較為常用,即每個設(shè)備的地址為7位。

通信速率:

標準模式:100kbit/s

快速模式:400kbit/s

高速模式:3.4Mbit/s

在通信中,首先發(fā)送起始條件 然后發(fā)送目標器件的7位地址+R/W位,等待應(yīng)答,發(fā)送/接收數(shù)據(jù),等待應(yīng)答/作出應(yīng)答,發(fā)送結(jié)束條件。

另外,存在廣播呼叫方式:發(fā)送個地址0x00,對所有從設(shè)備進行通信(不是所有器件都適用)

?

以MPU6050慣性傳感器為例,編寫模擬I2C的主機程序

在芯片手冊中找到描述如下

2.1編寫分段函數(shù)

II1_SDA_HGH-拉高數(shù)據(jù)線

II1_SDA_LOW-拉低數(shù)據(jù)線

II1_SCL_HIGH-拉高時鐘線

II1_SCL_LOW-拉低數(shù)據(jù)線

II1_SDA_DATA-讀取SDA線上的電平

IIC_Delay(x):定義一個x*4us的延時函數(shù)

2.1.1發(fā)起開始命令(Start condition)

  I2C總線平常處于空閑狀態(tài),SDA和SCL均為高電平。發(fā)起開始命令的做法是,SDA從高到低跳變,I2C總線從空閑->忙  

  void IIC_WriteStartCondition(void)

  {

    IIC1_SDA_HIGH;

    IIC1_SCK_HIGH; //如圖開始的時候兩個數(shù)據(jù)都處于高電平

    IIC_Delay(2); //延時一段時間后

    IIC1_SDA_LOW; //SDA先與SCL拉低,即為起始條件

    IIC_Delay(2); ????//延時一段時間后

    IIC1_SCK_LOW; //SCL拉低,并開始第一針數(shù)據(jù)(ADDRESS)的收發(fā),也是起始條件結(jié)束

    IIC_Delay(1); //延時半個周期為下一個函數(shù)作準備

  }

?

2.1.2數(shù)據(jù)傳輸函數(shù)

  數(shù)據(jù)傳輸中,SDA電平改變只能發(fā)生在SCL為低的期間,根據(jù)時序圖,可以知道在發(fā)送起始條件后需要發(fā)送從機地址和寫位,表示對總線上相應(yīng)的從機進行寫操作:

  void I2C_WriteByteDataToSlave(uint8_t data)

  {

    IIC1_SCK_LOW //再次拉低數(shù)據(jù)線,可以忽略

    for(i=0;i<8;i++) //發(fā)送一個字節(jié)(8位數(shù)據(jù))

    {

      (data & 0x80) ? IIC1_SDA_HIGH : IIC1_SDA_LOW;//判斷數(shù)據(jù)最高位是否為1,若是拉高數(shù)據(jù)線,否則拉低數(shù)據(jù)線,表示傳輸字節(jié)1/0

      data <<= 1; 把數(shù)據(jù)左移1位,把剛剛發(fā)送完的數(shù)據(jù)剔除

      IIC1_SCK_HIGH;//拉高時鐘線表示1個位傳輸結(jié)束

      IIC_Delay(1); ??//延時半個周期

      IIC1_SCK_LOW; //SCL拉到低電平準備發(fā)送下一位數(shù)據(jù)

      IIC_Delay(1);

    }

  }

2.1.3 等待應(yīng)答

  I2C發(fā)送第一幀數(shù)據(jù)完畢后,需要等待從機返回應(yīng)答以確保它收到了信息。等待應(yīng)答的時候主機釋放SDA線,從機接管SDA并保證其低電平直到下一個SCL高電平結(jié)束,編程上這里使第9個SCL信號拉高后,一直讀取SDA信號直到出現(xiàn)低電平才跳出,最后主機拉低SCL,拉高SDA

  Uint8_t IIC_WaitSlaveAsck(void)

  {

    uint8_t tim = 0;

    IIC1_SCK_HIGH; ??//拉高SCL

    while(IIC1_SDA_DATA) //當數(shù)據(jù)線為高電平

    {

      tim++;

      Delay(1);

      if(tim > 50) //設(shè)計一個倒計時,超過50ms則認為從機無應(yīng)答,I2c出錯,返回1

???    ?????{

?????    ???????tim=0;

??????    ??????I2CERR++;

        return 1;

????    ????}

    }

    IIC_Delay(1);

    IIC1_SCK_LOW;

    IIC1_SDA_HIGH;

    IIC_Delay(1);

    return 0; //返回0

  }

2.1.4發(fā)起停止(Stop condition)

  停止信號后釋放I2C總線,總線返回空閑狀態(tài),操作是當SCL在高電平時,SDA發(fā)生從第到高的跳變

  

  void IIC_StopCondition(void)

  {

    IIC1_SDA_LOW;//先讓SDA處于低電平

    IIC1_SCK_HIGH;//拉高SCL

    IIC_Delay(2);//延時

    IIC1_SDA_HIGH;//SDA發(fā)生從低到高的跳變

    IIC_Delay(2);//延時一段時間等待通信結(jié)束

  }

2.1.5數(shù)據(jù)接收

  當我們進行MPU6050的讀取操作時,需要接收來自MPU6050的數(shù)據(jù),具體操作為如2.1.1發(fā)起Start ?然后發(fā)送地址及讀取位,之后產(chǎn)生SCL時鐘信號,并釋放SDA線由MPU6050接管,在SCL高電平接收數(shù)據(jù)  

  uint8_t IIC_ReadByteDataFromSlave(void)

  {

    uint8_t i,data=0;?

    for(i=0;i<8;i++)

    {

      IIC1_SCK_HIGH; //拉高時鐘線

      IIC_Delay(1); //延時一個周期

      data <<= 1; //把數(shù)據(jù)左移一位

      data |= IIC1_SDA_DATA; //把新來的數(shù)據(jù)加在位

      IIC1_SCK_LOW; //拉低時鐘線

      IIC_Delay(1); //延時

    }

    return data; //返回接收到的數(shù)據(jù)

  }

2.1.6主機應(yīng)答

  在接收到MPU6050的數(shù)據(jù)時,需要作出應(yīng)答(連讀模式時)來告訴MPU6050繼續(xù)發(fā)送下一幀數(shù)據(jù),或者不作出應(yīng)答直接發(fā)出Stop condition表示通信結(jié)束

  void IIC_MastAsckToSlave(void)

  {

    IIC1_SCK_LOW;

    IIC1_SDA_LOW;

    // IIC_Delay(1);

    IIC1_SCK_HIGH;

    IIC_Delay(1);

    IIC1_SCK_LOW;

    IIC1_SDA_HIGH;

    IIC_Delay(1);

  }

?

  void IIC_MastNoteAsckToSlave(void)

  {

    IIC1_SCK_LOW;

    IIC1_SDA_HIGH;

    // IIC_Delay(1);

    IIC1_SCK_HIGH;

    IIC_Delay(1);

    IIC1_SCK_LOW;

    IIC_Delay(1);

  }

2.2編寫整段讀取

2.2.1 單字節(jié)寫:

本段函數(shù)中分為8個部分,分別是:產(chǎn)生起始信號、寫入從機地址+寫位、等待應(yīng)答、寫入寄存器地址、等待應(yīng)答、寫入數(shù)據(jù)、等待應(yīng)答、產(chǎn)生停止信號。根據(jù)已寫成的函數(shù)進行組合。

void MPU6050_SingleByteWrite_Soft( I2C_TypeDef* I2Cx, uint8_t RegisterAddress, uint8_t Data )?

{

  IIC_WriteStartCondition(); ? ???//1?

  IIC_WriteByteDataToSlave(MPU6050_I2C_ADDRESS);//2?

  IIC_WaitSlaveAsck(); ???//3?

  IIC_WriteByteDataToSlave(RegisterAddress); ???????//4?

  IIC_WaitSlaveAsck(); ???//5?

  IIC_WriteByteDataToSlave(Data); ???//6?

  IIC_WaitSlaveAsck(); ???//7

  IIC_StopCondition(); ???//8?

}

2.2.2爆發(fā)寫(連續(xù)寫)

關(guān)鍵在于發(fā)送寄存器地址以后可以一直只發(fā)送數(shù)據(jù)進行寫入,利用for循環(huán)體。

void MPU6050_BurstWrite_Soft( I2C_TypeDef* I2Cx, uint8_t RegisterAddress, uint8_t* DataPointer, uint8_t DataLength )

?

{

  u8 i;?

  IIC_WriteStartCondition();?

  IIC_WriteByteDataToSlave(MPU6050_I2C_ADDRESS);?

  IIC_WaitSlaveAsck();?

  IIC_WriteByteDataToSlave(RegisterAddress);?

  IIC_WaitSlaveAsck();

  for(i=0;i<DataLength;i++)?

  {

    IIC_WriteByteDataToSlave(*(DataPointer+i));

    IIC_WaitSlaveAsck(); ? ? ? ?

  }?

  IIC_StopCondition(); ? ??

}

2.2.3單字節(jié)讀

本函數(shù)分為11段:分別是 起始條件、從機地址加寫、等待應(yīng)答、寄存器地址、等待從機應(yīng)答、再次發(fā)送起始條件、從機地址加讀、等待應(yīng)答、讀取數(shù)據(jù)、不應(yīng)答,停止條件

uint8_t MPU6050_SingleByteRead_Soft( I2C_TypeDef* I2Cx, uint8_t RegisterAddress )

{

  uint8_t Data;

  IIC_WriteStartCondition();

  IIC_WriteByteDataToSlave(MPU6050_I2C_ADDRESS);

  IIC_WaitSlaveAsck();?

  IIC_WriteByteDataToSlave(RegisterAddress);?

  IIC_WaitSlaveAsck();

  IIC_WriteStartCondition();

  IIC_WriteByteDataToSlave(MPU6050_I2C_ADDRESS+1);?

  IIC_WaitSlaveAsck();?

  Data = IIC_ReadByteDataFromSlave();?

  MastNoteAsckToSlave();

  IIC_StopCondition();

  return Data;?

}

2.2.4爆發(fā)式讀(連讀)

根據(jù)單字節(jié)讀稍作修改

void MPU6050_BurstRead_Soft( I2C_TypeDef* I2Cx, uint8_t RegisterAddress, uint8_t* DataPointer, uint8_t DataLength )

{

  uint8_t i;

  IIC_WriteStartCondition();

  IIC_WriteByteDataToSlave(MPU6050_I2C_ADDRESS);

  IIC_WaitSlaveAsck();

  IIC_WriteByteDataToSlave(RegisterAddress);

  IIC_WaitSlaveAsck();

  IIC_WriteStartCondition();

  IIC_WriteByteDataToSlave(MPU6050_I2C_ADDRESS+1);

  IIC_WaitSlaveAsck();

  for(i=0;i<DataLength-1;i++)

  {

    ?* (DataPointer+i)=IIC_ReadByteDataFromSlave();

    MastAsckToSlave();

????}

  * (DataPointer+i)=IIC_ReadByteDataFromSlave();

  MastNoteAsckToSlave();

  IIC_StopCondition();

}?

?

?

三、SPI通信

3.1 SPI重要參數(shù)

SPI為4線的串行通信協(xié)議

分別為

1、SCK:發(fā)生時鐘信號,由主機發(fā)出信號

2、MISO:主進從出,主機的接收信號端,由從機發(fā)出信號

3、MOSI:主出從進,主機的發(fā)送信號端,由主機發(fā)出信號

4、CS:片選,主機控制(拉低表示傳輸開始)

也有部分設(shè)備省略CS端,稱為3線SPI

首先SPI的兩個參數(shù)會導致程序編寫的不同

1 時鐘極性(CPOL)

2 時鐘相位(CPHA)

當CPOL=0的時候,串行同步時鐘的空閑狀態(tài)為低電平

當CPOL=1的時候,串行同步時鐘的空閑狀態(tài)為高電平

如下圖所示:紅框內(nèi)表示空閑時間電平

當CPHA=0,串行同步時鐘的第一個跳變沿(上升下降沿)數(shù)據(jù)被采樣

當CPHA=1,串行同步時鐘的第二個跳變沿(上升下降沿)數(shù)據(jù)被采樣

如下圖所示:紅框內(nèi)表示1還是2跳變沿采樣

3.2模擬SPI串行通信

設(shè)定CPOL=0;CPHA=0;數(shù)據(jù)從MSB開始發(fā)送,如下圖所示

3.2.1 主機部分

注釋:以下程序出現(xiàn)到的函數(shù)

Uint8_t:定義為unsigned char 類型

CS_HIGH():表示拉高CS信號

CS_LOW():表示拉低CS信號

SCK_HIGH():表示拉高時鐘線

SCK_LOW():表示拉低時鐘線

MOSI_HIGH():表示拉高MOSI信號

MOSI_LOW():表示拉低MOSI信號

READ_MISO():表示讀取MISO信號

SPI_DELAY(x):表示延時x*1/2個時鐘周期

3.2.1.1 編寫讀一字節(jié)的函數(shù)

uint8_t SPI_ReadWriteByte(uint8_t Data)

{

  uint8_t i;

  uint8_t ReturnData;

?

  CS_LOW();//拉低片選信號準備開始數(shù)據(jù)傳輸

  SPI_DELAY(2);//等待從機反應(yīng)過來

  for(i=0;i<8;i++)

  {

    If(Data&0x80==0x80)

      MOSI_HIGH();//如果最高位為高電平則

    else

      MOSI_LOW();//如果最高位為低電平則拉低MOSI

    Data=Data<<1; ??//把數(shù)據(jù)左移一位準備發(fā)送下一位數(shù)據(jù)

    SPI_DELAY(1):

    SCK_HIGH(): ???//在上升沿數(shù)據(jù)生效

    ReturnData<<1;

    ReturnData|=READ_MISO()://把新接收到的數(shù)據(jù)作為次高位

    SPI_DELAY(1):

    SCL_LOW(); ???//拉低時鐘信號

  }

  SPI_DELAY(2);//延時一段時間等待從機完全接收完成

  CS_HIGH();//拉高片選信號表示傳輸結(jié)束

  return ReturnData;//返回接收到的數(shù)據(jù)

}

3.2.1 從機部分

MISO_HIGH():表示拉高MISO信號

MISO_LOW():表示拉低MISO信號

READ_MOSI():表示讀取MOSI信號

READ_SCK():表示讀取SCK信號

?

3.2.2.1 編寫讀一字節(jié)的函數(shù)

uint8_t SPI_ReadWriteByte(uint8_t Data)

{

  uint8_t i;

  uint8_t ReturnData;

?

  for(i=0;i<8;i++)

  {

    If(data&0x80==0x80)

      MISO_HIGH():

    else

      MISO_LOW():

    Data<<1;

    While(!READ_SCK);//等待上升沿

    ReturnData<<1;

    ReturnData|=READ_MISO()://把新接收到的數(shù)據(jù)作為次高位

    While(READ_SCK);//等待下一次低電平的到來

  }

  Return ReturnData;

}

?

四、CAN通信

  4.1CAN總線簡介

  在這里介紹四種通信中最特別的通信方式,常常用于汽車電子中,其特色只需要鏈接2線CAN_LOW和CAN_HIGH(不用接地線),以及是一種多主的通信方式,具有抗干擾能力強、通信速度高(常用125K、500K)、通信距離遠、自動診斷剔除錯誤設(shè)備等等的優(yōu)點。是多機組網(wǎng)通信的優(yōu)秀形式。

  它也存在缺點:每幀攜帶的數(shù)據(jù)較少(最多8個字節(jié))、需要外掛設(shè)備

  4.2CAN總線電平

    CAN通信使用的兩根線(常以雙絞線形式出現(xiàn))CAN_LOW和CAN_H

    (此處補圖)

    顯性電平:邏輯0:CAN_LOW輸出1.5V ?CAN_HIGH輸出3.5V,兩線電壓差2V

    隱性電平:邏輯1:CAN_HIGH輸出2.5V CAN_HIGH輸出2.5V ,兩線電壓差0V

    

    電氣連接:

    上拉模式:同I2C的連接方式,CAN_L 和CAN_H接上拉電阻到電源

    回環(huán)模式:在CAN_L和CAN_H之間連接電阻

    (此處補圖)

  4.4CAN總線數(shù)據(jù)幀

    CAN總線協(xié)議具有固定報文形式,以下對其進行詳細介紹

    首先是4種基本幀:

    一、標準數(shù)據(jù)幀

    (此處補圖)

    組成:1位SOF+11位仲裁段(標準ID+RTR)+6位控制段(IDE+r0+DLC)+ 0~64位數(shù)據(jù)段(MSB在前)+15位CRC校驗段+ACK段(ACK槽+ACK界定符)+EOF

      中裁段:

        ID段:ID號越小,表示具有越高的優(yōu)先級,當CAN總線同時有兩個主機發(fā)送信息時,優(yōu)先級高的信息具有有限傳送資格

        RTR:遠程發(fā)送請求位:標準幀中為顯性

      控制段:

        IDE:識別符擴展位:在標準幀中為控制段,并為顯性。

        R0:保留

        DLC:

      

    二、擴展數(shù)據(jù)幀

    (此處補圖)

    組成:SOF+29位仲裁段(標準ID+RRR+IDE+擴展ID+RTR)+6位控制段(r0+r1+DLC)+ 0~64位數(shù)據(jù)段(MSB在前)+15位CRC校驗段+ACK段(ACK槽+ACK界定符)+EOF

    三、標準遠程幀(標準遙控幀)

    (此處補圖)

    組成同標準數(shù)據(jù)幀,但是沒有數(shù)據(jù)段

    組成:1位SOF+11位仲裁段(標準ID+RTR)+6位控制段(IDE+r0+DLC)+15位CRC校驗段+ACK段(ACK槽+ACK界定符)+EOF

    四、擴展遠程幀(擴展遙控幀)

    (此處補圖)

    組成同擴展數(shù)據(jù)幀,但是沒有數(shù)據(jù)段

    組成:SOF+29位仲裁段(標準ID+RRR+IDE+擴展ID+RTR)+6位控制段(r0+r1+DLC))+15位CRC校驗段+ACK段(ACK槽+ACK界定符)+EOF

?

    

  

轉(zhuǎn)載于:https://www.cnblogs.com/HongYi-Liang/p/7058587.html

總結(jié)

以上是生活随笔為你收集整理的常用串行通信的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。