STM32讀寫24c02總結
這兩天學習STM32的IIC,實現讀寫24c02的資料,對IIC不是那麼的陌生,在這裡,將這兩天的學習的流程總結下,整理整理自己的思路。
簡潔
IIC是一種通訊協議,通訊方式相對比較簡單,主要有兩條線,SDA,SCL。SDA是資料匯流排,上面走命令和資料,而SCL只是一條時鐘線,其保證資料按照時鐘節拍來進行傳輸。IIC上面可以外掛很多的器件,每一個器件對應者不同的地址,通過地址將不同的器件進行分開,保證不同晶片之間的資料傳輸,由於每一個器件都是可以獨立的收發,故,每一個器件都是主機/從機。
資料傳輸流程
大致的一個數據傳輸流程是:主機向SDA線上傳送一個起始訊號,表示有訊號進行傳輸,此時所有連線到IIC總線上的晶片都處於接收狀態,接下來,主機發送想要與其進行資料傳輸的從機地址訊號,所有的從機都會接收到該地址訊號並和自己固有的地址訊號進行匹配,當配對成功時,接下來就在時鐘訊號的帶動下進行資料傳輸,資料的傳輸是按照每8位一個單元進行資料的傳輸。每一位的傳輸過程中,在SCL高電平期間,一定要保證SDA數值的穩定,否則會出現出錯的情況,SDA數值的改變發生在SCL的低電平期間。最終8位全部傳輸完畢,從機產生一個應答訊號給主機,主機在接收到該應答訊號後決定接下來是傳送一組新的資料還是終止傳送。
程式碼分析
分析之前,將一些定義告訴大家:
#define IIC_SCL_H GPIO_SetBits(GPIOB,GPIO_Pin_6) #define IIC_SDA_H GPIO_SetBits(GPIOB,GPIO_Pin_7) #define IIC_SCL_L GPIO_ResetBits(GPIOB,GPIO_Pin_6) #define IIC_SDA_L GPIO_ResetBits(GPIOB,GPIO_Pin_7) #define READ_SDA GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)
①起始訊號
SDA、SCL線預設是高,表示匯流排處於空閒狀態,接著SDA線被主機拉低,表示主機有訊號進行傳輸,要麼是發資料,或者是要進行讀資料,當SDA線拉低之後,SCL線也同樣被拉低,準備接下來的資料傳輸。此開始訊號的產生如下:
//IIC起始訊號
void IIC_Start(void)
{
IIC_SCL_H;
IIC_SDA_H;
delau_us(5);
IIC_SDA_L;
delau_us(5);
IIC_SCL_L;
}
②終止訊號
終止訊號:就是在SCL為高電平時,SDA出現一個上升沿的跳變,即表示終止訊號
//產生IIC停止訊號
void IIC_Stop(void)
{
IIC_SDA_L;
IIC_SCL_L;
delau_us(5);
IIC_SCL_H;
delau_us(4);
IIC_SDA_H;
delau_us(5);
}
③等待應答訊號
主機將一組資料傳送完畢,接下來就進入等待從機發送應答訊號到來,從機會在第9個時鐘訊號時,傳送應答訊號,此應答訊號就是將SDA訊號拉低。
u8 IIC_Wait_Ack(void)
{
u8 flag_ack=0;
IIC_SCL_L;
IIC_SDA_H;
delau_us(5);
IIC_SCL_H;
delau_us(5);
while(READ_SDA && flag_ack<4)
{
flag_ack++;
delau_us(1);
}
if(flag_ack>=4)
{
IIC_Stop();
return 1;
}
IIC_SCL_L;
return 0;
}
④產生應答訊號
有效應答位ACK的要求是,接收器在第9個時鐘脈衝之前的低電平期間將SDA線拉低,並且確保在該時鐘的高電平期間為穩定的低電平。
void IIC_Ack(void)
{
IIC_SCL_L;
IIC_SDA_L;
delau_us(5);
IIC_SCL_H;
delau_us(5);
}
⑤不產生應答訊號
void IIC_NAck(void)
{
IIC_SCL_L;
IIC_SDA_H;
delau_us(4);
IIC_SCL_H;
delau_us(4);
}
⑥傳送接收資料
時鐘訊號為高電平期間:資料線上的資料必須保持穩定
時鐘訊號為低電平期間:資料線上的高或低電平狀態才允許變化。
void IIC_Send_Byte(u8 txd)
{
u8 t=0;
/*時鐘訊號拉低,資料準備好再拉高進行傳輸*/
for(t = 0; t < 8; t++)
{
IIC_SCL_L;
if(txd&0x80)
IIC_SDA_H;
else
IIC_SDA_L;
delau_us(5);
/*SCL拉高傳輸資料*/
IIC_SCL_H;
delau_us(5);
txd <<= 1;
}
}
u8 IIC_Read_Byte(void)
{
u8 receive = 0;
u8 i=8;
for(i = 0; i < 8; i++ )
{
/*SCL拉低*/
IIC_SCL_L;
delau_us(4);
/*拉高SCL產生一個有效的時鐘訊號*/
IIC_SCL_H;
/*讀取總線上的資料*/
receive<<=1;
if(READ_SDA)
receive|=1;
delau_us(4);
}
return receive;
}
針對24c02進行程式設計
1、在AT24C02指定地址讀出一個數據
先來看AT24C02的隨機讀資料的時序圖
此時序圖上需要注意兩個地方,箭頭所標記的兩次開始訊號,以及橢圓圈起來的寫訊號和讀訊號,接下來就分析該過程
首先,傳送一個開始訊號,接下來發送器件的地址,注意最後一位為Write標誌位(0),等待應答,然後傳送要讀的地址,等待應答,又要傳送一個起始訊號,傳送器件的地址,注意此時,最後一位為Read標誌位(1),等待應答,接下來資料就可以讀回來了。
器件的地址:
地址按照這個來進行設定,AT24CXX,這個XX即表示儲存量XX(K),很顯然AT24C02為2K,有256Byte,A2,A1,A0定義看晶片,如下
故,AT24C02的寫地址為0XA0,讀地址為0XA1,到這裡,任督二脈已打通,接下來,上原始碼
#include "24c02.h"
#include "iic.h"
#include<stdio.h>
#include<string.h>
//匯流排初始化
void AT_24c02_int(void)
{
IIC_Init();
}
//data_addr 位元組地址
//data 資料
void AT_24c02_write_data(u8 data_addr,u8 data)
{
u8 ack_flag=0;
IIC_Start();
IIC_Send_Byte(0xa0);
ack_flag=IIC_Wait_Ack();
IIC_Send_Byte(data_addr);
ack_flag=IIC_Wait_Ack();
IIC_Send_Byte(data);
ack_flag=IIC_Wait_Ack();
IIC_Stop();
}
u8 AT_24c02_read_data(u8 data_addr)
{
u8 ack_flag=0;
u8 data=0;
IIC_Start();
IIC_Send_Byte(0xa0);
ack_flag=IIC_Wait_Ack();
IIC_Send_Byte(data_addr);
ack_flag=IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(0xa1);
ack_flag=IIC_Wait_Ack();
data=IIC_Read_Byte();
IIC_NAck();
IIC_Stop();
return data;
}
主函式:
#include "key.h"
#include "led.h"
#include "beep.h"
#include "interrupt.h"
#include "usart.h"
#include "timecatch.h"
#include "Adc.h"
#include <stdio.h>
#include "iic.h"
#include "24c02.h"
u8 key_flag=0;
u8 usart_rx_buf[20]={0};
u8 TIM4CH3_CAPTURE_STA=0;
u32 temp=0;
u16 ad_result=0;
u8 ad_temp[3];
int i;
int main(void)
{
delay_init();
gpio_beep_configuration();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
exti_configuration();
gpio_led_configuration();
gpio_key_configuration();
exti_nvic_configuration();
usart_configuration();
AT_24c02_int();
AT_24c02_write_data(0x01,0x55);
delau_ms(10);
key_flag=AT_24c02_read_data(0x01);
usart_send(&key_flag);
}