新建工程,在Hardware目錄下添加myiic.c和24cxx.c,其中myiic.c文件存放iic驅(qū)動(dòng)代碼,24cxx.c文件存放24C02驅(qū)動(dòng)代碼。 編輯myiic.c文件: #include "myiic.h" #include "delay.h" //初始化IIC void IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );//PB時(shí)鐘使能 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 GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); //PB6,PB7 輸出高 } //產(chǎn)生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總線,準(zhǔn)備發(fā)送或接收數(shù)據(jù) } //產(chǎn)生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;//發(fā)送I2C總線結(jié)束信號 delay_us(4); } //等待應(yīng)答信號到來 //返回值:1,接收應(yīng)答失敗 // 0,接收應(yīng)答成功 u8 IIC_Wait_Ack(void) { u8 ucErrTime=0; SDA_IN(); //SDA設(shè)置為輸入 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;//時(shí)鐘輸出0 return 0; } //產(chǎn)生ACK應(yīng)答 void IIC_Ack(void) { IIC_SCL=0; SDA_OUT(); IIC_SDA=0; delay_us(2); IIC_SCL=1; delay_us(2); IIC_SCL=0; } //不產(chǎn)生ACK應(yīng)答 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發(fā)送一個(gè)字節(jié) //返回從機(jī)有無應(yīng)答 //1,有應(yīng)答 //0,無應(yīng)答 void IIC_Send_Byte(u8 txd) { u8 t; SDA_OUT(); IIC_SCL=0;//拉低時(shí)鐘開始數(shù)據(jù)傳輸 for(t=0;t<8;t++) { IIC_SDA=(txd&0x80)>>7; txd<<=1; delay_us(2); //對TEA5767這三個(gè)延時(shí)都是必須的 IIC_SCL=1; delay_us(2); IIC_SCL=0; delay_us(2); } } //讀1個(gè)字節(jié),ack=1時(shí),發(fā)送ACK,ack=0,發(fā)送nACK u8 IIC_Read_Byte(unsigned char ack) { unsigned char i,receive=0; SDA_IN();//SDA設(shè)置為輸入 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();//發(fā)送nACK else IIC_Ack(); //發(fā)送ACK return receive; } 該部分為IIC驅(qū)動(dòng)代碼,實(shí)現(xiàn)包括IIC的初始化(IO口)、IIC開始、IIC結(jié)束、ACK、IIC讀寫等功能,在其他函數(shù)里面,只需要調(diào)用相關(guān)的IIC函數(shù)就可以和外部IIC器件通信了,這里并不局限于24C02,該段代碼可以用在任何IIC設(shè)備上。 接下來編輯myiic.h文件: #define SDA_IN() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=8<<12;} #define SDA_OUT() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=3<<12;} 然后編輯24cxx.c文件: #include "24cxx.h" #include "delay.h" //初始化IIC接口 void AT24CXX_Init(void) { IIC_Init(); } //在AT24CXX指定地址讀出一個(gè)數(shù)據(jù) //ReadAddr:開始讀數(shù)的地址 //返回值:讀到的數(shù)據(jù) u8 AT24CXX_ReadOneByte(u16 ReadAddr) { u8 temp=0; IIC_Start(); if(EE_TYPE>AT24C16) { IIC_Send_Byte(0XA0);//發(fā)送寫命令 IIC_Wait_Ack(); IIC_Send_Byte(ReadAddr>>8);//發(fā)送高地址 }else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1)); //發(fā)送器件地址0XA0,寫數(shù)據(jù) IIC_Wait_Ack(); IIC_Send_Byte(ReadAddr%256); //發(fā)送低地址 IIC_Wait_Ack(); IIC_Start(); IIC_Send_Byte(0XA1); //進(jìn)入接收模式 IIC_Wait_Ack(); temp=IIC_Read_Byte(0); IIC_Stop();//產(chǎn)生一個(gè)停止條件 return temp; } //在AT24CXX指定地址寫入一個(gè)數(shù)據(jù) //WriteAddr :寫入數(shù)據(jù)的目的地址 //DataToWrite:要寫入的數(shù)據(jù) void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite) { IIC_Start(); if(EE_TYPE>AT24C16) { IIC_Send_Byte(0XA0);//發(fā)送寫命令 IIC_Wait_Ack(); IIC_Send_Byte(WriteAddr>>8);//發(fā)送高地址 }else IIC_Send_Byte(0XA0+((WriteAddr/256)<<1)); //發(fā)送器件地址0XA0,寫數(shù)據(jù) IIC_Wait_Ack(); IIC_Send_Byte(WriteAddr%256); //發(fā)送低地址 IIC_Wait_Ack(); IIC_Send_Byte(DataToWrite); //發(fā)送字節(jié) IIC_Wait_Ack(); IIC_Stop();//產(chǎn)生一個(gè)停止條件 delay_ms(10); } //在AT24CXX里面的指定地址開始寫入長度為Len的數(shù)據(jù) //該函數(shù)用于寫入16bit或者32bit的數(shù)據(jù). //WriteAddr :開始寫入的地址 //DataToWrite:數(shù)據(jù)數(shù)組首地址 //Len :要寫入數(shù)據(jù)的長度2,4 void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len) { u8 t; for(t=0;t<Len;t++) { AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff); } } //在AT24CXX里面的指定地址開始讀出長度為Len的數(shù)據(jù) //該函數(shù)用于讀出16bit或者32bit的數(shù)據(jù). //ReadAddr :開始讀出的地址 //返回值:數(shù)據(jù) //Len :要讀出數(shù)據(jù)的長度2,4 u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len) { u8 t; u32 temp=0; for(t=0;t<Len;t++) { temp<<=8; temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1); } return temp; } //檢查AT24CXX是否正常 //這里用了24XX的最后一個(gè)地址(255)來存儲標(biāo)志字. //如果用其他24C系列,這個(gè)地址要修改 //返回1:檢測失敗 //返回0:檢測成功 u8 AT24CXX_Check(void) { u8 temp; temp=AT24CXX_ReadOneByte(255);//避免每次開機(jī)都寫AT24CXX if(temp==0X55)return 0; else//排除第一次初始化的情況 { AT24CXX_WriteOneByte(255,0X55); temp=AT24CXX_ReadOneByte(255); if(temp==0X55)return 0; } return 1; } //在AT24CXX里面的指定地址開始讀出指定個(gè)數(shù)的數(shù)據(jù) //ReadAddr :開始讀出的地址對24c02為0~255 //pBuffer :數(shù)據(jù)數(shù)組首地址 //NumToRead:要讀出數(shù)據(jù)的個(gè)數(shù) void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead) { while(NumToRead) { *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++); NumToRead--; } } //在AT24CXX里面的指定地址開始寫入指定個(gè)數(shù)的數(shù)據(jù) //WriteAddr :開始寫入的地址對24c02為0~255 //pBuffer :數(shù)據(jù)數(shù)組首地址 //NumToWrite:要寫入數(shù)據(jù)的個(gè)數(shù) void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite) { while(NumToWrite--) { AT24CXX_WriteOneByte(WriteAddr,*pBuffer); WriteAddr++; pBuffer++; } } 這部分代碼實(shí)際就是通過IIC接口來操作24Cxx芯片,理論上是可以支持24Cxx所有系列的芯片的(地址引腳必須都設(shè)置為0),但是本實(shí)驗(yàn)只測試了24C02,其他器件有待測試。 編輯main.c函數(shù): //要寫入到24c02的字符串?dāng)?shù)組 const u8 TEXT_Buffer[]={"WarShipSTM32 IIC TEST"}; #define SIZE sizeof(TEXT_Buffer) int main(void) { u8 key; u16 i=0; u8 datatemp[SIZE]; delay_init();//延時(shí)函數(shù)初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設(shè)置中斷優(yōu)先級分組為組2 uart_init(115200);//串口初始化為115200 LED_Init();//初始化與LED連接的硬件接口 LCD_Init();//初始化LCD KEY_Init();//按鍵初始化 AT24CXX_Init();//IIC初始化 POINT_COLOR=RED;//設(shè)置字體為紅色 LCD_ShowString(30,50,200,16,16,"WarShip STM32"); LCD_ShowString(30,70,200,16,16,"IIC TEST"); LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK"); LCD_ShowString(30,110,200,16,16,"2015/1/15"); LCD_ShowString(30,130,200,16,16,"KEY1:Write KEY0:Read");//顯示提示信息 while(AT24CXX_Check())//檢測不到24c02 { LCD_ShowString(30,150,200,16,16,"24C02 Check Failed!"); delay_ms(500); LCD_ShowString(30,150,200,16,16,"Please Check! "); delay_ms(500); LED0=!LED0;//DS0閃爍 } LCD_ShowString(30,150,200,16,16,"24C02 Ready!"); POINT_COLOR=BLUE;//設(shè)置字體為藍(lán)色 while(1) { key=KEY_Scan(0); if(key==KEY1_PRES)//KEY1按下,寫入24C02 { LCD_Fill(0,170,239,319,WHITE);//清除半屏 LCD_ShowString(30,170,200,16,16,"Start Write 24C02...."); AT24CXX_Write(0,(u8*)TEXT_Buffer,SIZE); LCD_ShowString(30,170,200,16,16,"24C02 Write Finished!");//提示傳送完成 } if(key==KEY0_PRES)//KEY1按下,讀取字符串并顯示 { LCD_ShowString(30,170,200,16,16,"Start Read 24C02.... "); AT24CXX_Read(0,datatemp,SIZE); LCD_ShowString(30,170,200,16,16,"The Data Readed Is: ");//提示傳送完成 LCD_ShowString(30,190,200,16,16,datatemp);//顯示讀到的字符串 } i++; delay_ms(10); if(i==20) { LED0=!LED0;//提示系統(tǒng)正在運(yùn)行 i=0; } } } 該段代碼通過KEY1按鍵來控制24C02的寫入,通過另外一個(gè)按鍵KEY0來控制24C02的讀取。并在LCD模塊上面顯示相關(guān)信息。 |