「STM32 」IIC通訊原理及其實驗

来源:https://www.cnblogs.com/cniot/archive/2019/08/09/11325324.html
-Advertisement-
Play Games

I2C兩線式串列匯流排通訊協議,它是由飛利浦開發的,主要用於連接微控制器及其外圍設備之間,它是由數據線SDA和信號線SCL構成的,可發送和接收數據即在MUC和I2C設備之間,I2C和I2C之間進行全雙工信號傳輸,高速I2C匯流排一般可達到400kbps。一般我們也稱為TWI介面。 ...


I2C兩線式串列匯流排通訊協議,它是由飛利浦開發的,主要用於連接微控制器及其外圍設備之間,它是由數據線SDA和信號線SCL構成的,可發送和接收數據即在MUC和I2C設備之間,I2C和I2C之間進行全雙工信號傳輸,高速I2C匯流排一般可達到400kbps。一般我們也稱為TWI介面。

I2C支持多主機模式:

即在這個主線上可以掛載n個I2C外設。

對於I2C協議,其實也很簡單,不要想的那麼複雜,其實就是電平的變換。我們可以人為的分為6個部分

整體時序圖:

各狀態:

  • 空閑狀態

I2C匯流排的SCK和SDA兩個線同時處於高電平的時候,規定為匯流排的空閑狀態,這個就是由匯流排上的上拉電阻把電平拉高的。

  • 起始信號

當SCL為高電平期間,SDA由高電平變成低電平,即為起始信號。啟動信號是一種電平跳變時序信號,不是一個電平信號。

  • 停止信號

當SCL為高電平期間,SDA由低電平變為高電平,即為停止信號。停止信號也是一種電平跳變時序信號,不是一個電平信號。

  • 應答信號

發送器每發送一個位元組(8bit)數據,就在時鐘脈衝(SCL)9期間釋放數據線(SDA),再由接收器來反饋一個應答信號,應答信號為低電平的時候,規定為有效應答位(ACK:應答位),表明接收器已經成功的接收了該位元組,應答信號為高電平時,規定為非應答位(NACK:非應答位),表示接收器沒有成功的接收該位元組。

對於反饋有效應答位(ACK):接收器在第9個時鐘脈衝之前的低電平期間將SDA拉低,並且保證在該時鐘的高電平期間,SDA為穩定的低電平。大家主要看圖,看看是不是這樣的。

要是接收器是主控器,那麼它收到最後一個位元組後,發送一個NACK信號,以通知被控發送器結束數據的發送,並且釋放SDA線,以便主控接收器發送一個停止信號。

  • 數據的有效性

時鐘信號(SCL)為高電平期間,數據線上的數據必須保持穩定,只有在時鐘信號(SCL)為低電平期間,數據線上的高電平或者低電平才能發生變化。

數據必須在時鐘信號(SCL)的上升沿到來之前就準備好,並且在數據信號的下降沿來到之前必須穩定。

  • 數據的傳輸

在SDA上的每一個位的數據的傳輸都需要一個時鐘脈衝,即在SCL串列時鐘的配合下,SDA上逐位的串列發送每一位數據。數據位的傳輸是邊沿觸發。

示例代碼講解

  • 初始化IIC

其實就是對兩個線的初始化,我這裡使用的是PA6和PA7,開始都設置為輸出,中途會改變PA7的輸入輸出屬性,小平頭,在空閑狀態,我們知道SCL和SDA是被拉高的,所以這個地方我們給高電平。

  • 產生IIC起始信號

將SDA線設置為輸出,然後SDA和SCL都設置為高電平,延遲4us,然後將SDA拉低,延遲4us,最後將SCL拉低。這其實就是協議規定的動作了。

  • 產生IIC停止信號

同樣的道理,和協議的時序保持一致就好了。

  • 等待應答信號到來

首先我們需要把SDA設置為輸入,因為接收方要給發射方返回一個應答信號的。小平頭 就是在SCL第9個高電平的時候,釋放信號線,先拉高,然後持續等待,是不是有應答信號返回,其實就是返回一個低電平,所以我們一直在檢測READ_SDA這個電平,持續一段時間,要是沒有返回的話,我們認為超時了,就直接停止協議了,

  • 產生應答信號

即在第9個時鐘周期內,SDA都為低電平,為應答

  • 不產生應答信號

即在第9個時鐘周期內,SDA都為高電平,為不應答

  • IIC發送一個位元組

發送數據,SDA設置為輸出。SCL拉低,SDA準備。

做一個8次迴圈,拿出1byte的數據,將你發送的數據和0x80作與運算,拿出最高位,然後右移7位,將這個數據放到最低位,這個數據要是1的話,那麼SDA輸出一個高電平,要是與後的結果為低電平的話,那麼SDA輸出一個低電平。這都屬於準備發送信號階段。

然後SCL拉高,完成數據的發送,然後SCL拉低,此時SDA也就可以拉低了,接著開始次高位的傳輸,直到傳輸完成。

  • 讀取數據

讀取數據,SDA要設置為輸入了。SCL開始為低電平,然後SCL為高電平,我們開始讀SDA上的數據,然後左移數據,將讀取的數據放在低位。然後檢測一下有沒有應答。

其實基本思路就是這樣了。我把源碼附上:

i2c.h

#ifndef __MYIIC_H
#define __MYIIC_H
#include "sys.h"
#include "stm32f10x_gpio.h"
//IO方向設置
#define SDA_IN() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}
//IO操作函數
#define IIC_SCL PBout(6) //SCL
#define IIC_SDA PBout(7) //SDA
#define READ_SDA PBin(7) //輸入SDA
//IIC所有操作函數
void IIC_Init(void); //初始化IIC的IO口
void IIC_Start(void); //發送IIC開始信號
void IIC_Stop(void); //發送IIC停止信號
void IIC_Send_Byte(u8 txd); //IIC發送一個位元組
u8 IIC_Read_Byte(unsigned char ack);//IIC讀取一個位元組
u8 IIC_Wait_Ack(void); //IIC等待ACK信號
void IIC_Ack(void); //IIC發送ACK信號
void IIC_NAck(void); //IIC不發送ACK信號
void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);
#endif

  

 本文轉自小平頭電子技術社區,轉載請註明出處:https://www.xiaopingtou.cn/article-104115.html

 

i2c.c

#include "myiic.h"
#include "delay.h"
//初始化IIC
void IIC_Init(void)
{					 
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );	//使能GPIOB時鐘
	 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推輓輸出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); 	//PB6,PB7 輸出高
}
//產生IIC起始信號
void IIC_Start(void)
{
	SDA_OUT(); //sda線輸出
	IIC_SDA=1;	 	 
	IIC_SCL=1;
	delay_us(4);
 	IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
	delay_us(4);
	IIC_SCL=0;//鉗住I2C匯流排,準備發送或接收數據 
}	 
//產生IIC停止信號
void IIC_Stop(void)
{
	SDA_OUT();//sda線輸出
	IIC_SCL=0;
	IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
 	delay_us(4);
	IIC_SCL=1; 
	IIC_SDA=1;//發送I2C匯流排結束信號
	delay_us(4);							 	
}
//等待應答信號到來
//返回值:1,接收應答失敗
// 0,接收應答成功
u8 IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	SDA_IN(); //SDA設置為輸入 
	IIC_SDA=1;delay_us(1);	 
	IIC_SCL=1;delay_us(1);	 
	while(READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	IIC_SCL=0;//時鐘輸出0 	 
	return 0; 
} 
//產生ACK應答
void IIC_Ack(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=0;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}
//不產生ACK應答		 
void IIC_NAck(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=1;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}					 				 
//IIC發送一個位元組
//返回從機有無應答
//1,有應答
//0,無應答			 
void IIC_Send_Byte(u8 txd)
{ 
 u8 t; 
	SDA_OUT(); 	 
 IIC_SCL=0;//拉低時鐘開始數據傳輸
 for(t=0;t<8;t++)
 { 
 //IIC_SDA=(txd&0x80)>>7;
		if((txd&0x80)>>7)
			IIC_SDA=1;
		else
			IIC_SDA=0;
		txd<<=1; 	 
		delay_us(2); 
		IIC_SCL=1;
		delay_us(2); 
		IIC_SCL=0;	
		delay_us(2);
 }	 
} 	 
//讀1個位元組,ack=1時,發送ACK,ack=0,發送nACK 
u8 IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA設置為輸入
 for(i=0;i<8;i++ )
	{
 IIC_SCL=0; 
 delay_us(2);
		IIC_SCL=1;
 receive<<=1;
 if(READ_SDA)receive++; 
		delay_us(1); 
 }					 
 if (!ack)
 IIC_NAck();//發送nACK
 else
 IIC_Ack(); //發送ACK 
 return receive;
}

  

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、命令行 可以通過運行 docker ,或者 docker help 命令得到命令行的幫助信息(我們以 CentOS 為操作環境為例): [root@iz2ze2bn5x2wqxdeq65wlpz ~]# docker help Usage: docker [OPTIONS] COMMA... ...
  • 解決也很簡單,在執行 ssh 命令的時候,多加一個參數即可,如下: ssh -p 2200 -o ServerAliveInterval=60 [email protected] #伺服器 8.8.8.8 的遠程埠號為2200 ...
  • 在centos7中安裝好docker以後,啟動成功,運行命令 docker info ,報錯: [root@iz2ze2bn5x2wqxdeq65wlpz ~]# docker info Client: Debug Mode: false Server: Containers: 4 Ru... ...
  • 命令概要 該命令設計用於在沒有用戶交互的情況下工作。 curl 是一個工具,用於傳輸來自伺服器或者到伺服器的數據。「向伺服器傳輸數據或者獲取來自伺服器的數據」 可支持的協議有(DICT、FILE、FTP、FTPS、GOPHER、HTTP、HTTPS、IMAP、IMAPS、LDAP、LDAPS、POP ...
  • dd 工具使用: dd 也是我們經常使用到的磁碟測試工具,Linux伺服器裝好系統之後,想要知道硬碟的讀寫是否能滿足服務的需要,如果不滿足硬碟的IO就是服務的一個瓶頸。我們可以使用dd命令簡單進行測試,更為專業的測試可以使用上面描述的fio 工具: time有計時作用,dd用於複製,從if讀出,寫到 ...
  • crontab中的%是換行的意思,在使用時需要使用\做轉義。 ...
  • 0x00 事件 因為本地的伺服器硬體出現故障,導致一臺 Windows 系統的開發環境掛了,且無法短時間內恢復狀態。 應急方案是使用了雲上的系統重建了開發環境。 開發人員說需要掛了的那台 Windows 開發環境中的資料庫數據,因為一些數據只有那個環境裡面有。於是找了把螺絲刀把硬碟拆下來,用移動硬碟 ...
  • Linux 運行jar包命令如下: 方式一: 特點:當前ssh視窗被鎖定,可按CTRL + C打斷程式運行,或直接關閉視窗,程式退出 那如何讓視窗不鎖定? 方式二 java -jar shareniu.jar & java -jar shareniu.jar & &代表在後臺運行。 特定:當前ssh ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...