STM32模拟IIC读写24C02程序代码
- 格式:docx
- 大小:17.30 KB
- 文档页数:8
//实验24C02连接在PF口//WP、A0、A1、A2都接地#include "stm32f10x_flash.h"#include "stm32f10x_gpio.h"#include "stm32f10x_rcc.h"#define AT24C02 0xa0 //AT24C02 地址/******************************** 变量定义---------------------------------------------------------*/GPIO_InitTypeDef GPIO_InitStructure; //GPIOErrorStatus HSEStartUpStatus;unsigned char Count1 , Count2;unsigned int USEC;static vu32 TimingDelay;unsigned char Readzfc;unsigned char pDat[8] = {0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55};unsigned char R_Dat[8];/*********************************声明函数-----------------------------------------------*/void RCC_Configuration(void);void SysTick_Configuration(void);void Delay_us_24C02(u32 nTime);/************************************24C02硬件接口******************************/#define SData GPIO_Pin_6 //I2C 时钟#define SCLK GPIO_Pin_7 //I2C 数据/********************************宏定义*******************************************/#define SCL(x) x ? GPIO_SetBits(GPIOF , SCLK) : GPIO_ResetBits(GPIOF , SCLK) #define SDA(x) x ? GPIO_SetBits(GPIOF , SData) : GPIO_ResetBits(GPIOF , SData)/********************************变量*******************************************/u8 ack;/*******************************************************************起动总线函数函数原型: void Start_I2c();功能: 启动I2C总线,即发送I2C起始条件.********************************************************************/ void Start_I2c(){SDA(1); //SDA=1; 发送起始条件的数据信号Delay_us_24C02(1);SCL(1); //SCL=1;Delay_us_24C02(5); //起始条件建立时间大于4.7us,延时SDA(0); //SDA=0; /*发送起始信号*/Delay_us_24C02(5); // 起始条件锁定时间大于4μsSCL(0); //SCL=0; /*钳住I2C总线,准备发送或接收数据 */Delay_us_24C02(2);}/*******************************************************************结束总线函数函数原型: void Stop_I2c();功能: 结束I2C总线,即发送I2C结束条件.********************************************************************/ void Stop_I2c(){SDA(0); //SDA=0; //发送结束条件的数据信号Delay_us_24C02(1); //发送结束条件的时钟信号SCL(1) ; //SCL=1; 结束条件建立时间大于4μsDelay_us_24C02(5);SDA(0); //SDA=1; 发送I2C总线结束信号Delay_us_24C02(4);}/*******************************************************************字节数据发送函数函数原型: void SendByte(UCHAR c);功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对此状态位进行操作.(不应答或非应答都使ack=0)发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
IIC总线有关24C02 实验程序;-----------------------------------------------------------------------;*程序名称:E2PROM.ASM? *;*功能说明:此程序为I2C总线E2PROM的读写实验程序,程序中将AT24C02 *;* 采用集几种模式写入,然后采用几种模式读出,将读出的数据 *;* 和写入的数据进行比较,如果有一个数据不相等则p1.0的LED *;* 指示灯点亮。
*;*创建时间:2003-06-23 *;*修改时间: *;---------------------------------------------------------------------------------------------------------SDA EQU P1.7 ;定义P1.7为I2C总线的数据线SCL EQU P1.6 ;定义P1.6为I2C总线的时钟线SLAW EQU 50H ;定义I2C器件的写地址存放空间SLAR EQU 51H ;定义I2C器件的读地址存放空间ADDRESS EQU 52H ;定义I2C器件的内部地址存放空间WR_DATA EQU 53H ;定义写数据的存放地址NB EQU 54H ;定义读写数据的数目的存放空间ORG 0000HLJMP MAINORG 0100HMAIN:MOV SP,#70H ;设定堆栈指针MOV SLAW,#0A0H ;初始化定义变量MOV SLAR,#0A1HMOV ADDRESS,#00HMOV WR_DATA,#00HMOV NB,#08HMOV R0,#30H ;写入缓冲区30H—38H赋初值MOV A,#00HMOV R5,NBW_DATA: MOV @R0,AINC R0INC ADJNZ R5,W_DATAMOV @R0,WR_DATAMOV R0,#30H ;写入缓冲区指向30HLCALL PAGE_WRITE ;对E2PROM进行页写操作LCALL DELAYMOV ADDRESS,#08H ;写入地址指向08LCALL BYTE_WRITE ;对E2PROM进行字节写操作LCALL DELAYMOV R0,#40H ;读出缓冲区指向40HMOV ADDRESS,#00H ;对E2PROM进行连续读操作LCALL RANDOM_READLCALL DELAYLCALL CURRENT_READ ;对E2PROM进行立即地址读操作INC R0MOV @R0,AMOV R0,#30HMOV R1,#40HMOV R5,#09HSETB P1.0COMP:MOV A,@R0 ;比较30H开始和40H开始的9个单元内容 MOV 08H,@R1CJNE A,08H,LED_OFF ;如有一个不相同,转到LED点亮并结束 INC R0INC R1DJNZ R5, COMPSETB P1.0 ;全部相同,熄灭LED,结束SJMP TEST_ENDLED_OFF:CLR P1.3TEST_END:SJMP $;—————————————————————————————————*;*函数名称:DELAY *;*功能描述:产生2MS的延时 *;*调用函数:无 *;*入口条件:无 *;*占用资源:R6、R7 * ;—————————————————————————————————* DELAY: ;2mS DELAYMOV R6,#0FFHDE1: MOV R7,#0AHDE2: DJNZ R7,DE2DJNZ R6,DE1RET ;—————————————————————————————————*;*函数名称:BYTE_WRITE *;*功能描述:对E2PROM指定地址写入数据 *;*调用函数:STA、WRBYT、CACK、STOP *;*入口条件:SLAW——I2C器件写地址 *;* ADDRESS——I2C的内部地址 *;* WR_DATA——写入的数据 *;*占用资源:ACC、F0、SLAW、ADDRESS、WR_DATA * ;—————————————————————————————————*BYTE_WRITE:LCALL STAMOV A,SLAWLCALL WRBYT ;写器件地址LCALL CACKJB F0,BYTE_WRITEMOV A,ADDRESS ;写入地址LCALL WRBYTLCALL CACKJB F0,BYTE_WRITEMOV A,WR_DATALCALL WRBYT ;写入数据LCALL CACKJB F0,BYTE_WRITELCALL STOPRET ;————————————————————————————————* ;*函数名称:PAGE_WRITE * ;*功能描述:对E2PROM指定的页写入8个字节的数据 * ;*调用函数:STA、WRBYT、CACK、STOP * ;*入口条件:SLAW——I2C器件写地址 * ;* ADDRESS——I2C的内部地址 * ;* R0——写数据的首地址 * ;*占用资源:ACC、R0、R7、F0、SLAW、ADDRESS、NB * ;————————————————————————————————* PAGE_WRITE:LCALL STAMOV A,SLAWLCALL WRBYT ;写器件的写地址LCALL CACKJB F0,PAGE_WRITEMOV A,ADDRESS ;写入地址LCALL WRBYTLCALL CACKJB F0,PAGE_WRITEMOV R7,#08HWR_16BYT: ;向E2PROM写入8个字节的数据MOV A,@R0LCALL WRBYTLCALL CACKJB F0,WR_16BYTINC R0DJNZ R7,WR_16BYTLCALL STOPRET ;————————————————————————————————* ;*函数名称:CURRENT_READ * ;*功能描述:读E2PROM当前地址计数器所指地址数据 *;*调用函数:STA、RDBYT、CACK、MNACK、STOP *;*入口条件:SLAR——I2C器件读地址 *;*占用资源:ACC * ;————————————————————————————————* CURRENT_READ:LCALL STAMOV A,SLARLCALL WRBYT ;写器件的读地址LCALL CACKJB F0,CURRENT_READLCALL RDBYT ;读数据LCALL MNACKLCALL STOPRET ;————————————————————————————————*;*函数名称:RANDOM_READ *;*功能描述:对E2PROM从指定地址读出NB个字节的数据 *;*调用函数:STA、WRBYT、CACK、STOP、MACK、MNACK *;*入口条件:SLAW——I2C器件的写地址 *;* SLAR——I2C器件的读地址 *;* ADDRESS——I2C的内部地址 *;* R0——读出数据存储区的首地址 *;*占用资源:ACC、F0、SLAW、SLAR、ADDRESS、R0 * ;————————————————————————————————*RANDOM_READ:LCALL STAMOV A,SLAWLCALL WRBYT ;写器件的写地址LCALL CACKJB F0,RANDOM_READMOV A,ADDRESSLCALL WRBYT ;读的内部地址LCALL CACKJB F0,RANDOM_READRDNBYT: LCALL STAMOV A,SLAR ;写读地址LCALL WRBYTLCALL CACKJB F0,RDNBYTRDN1: LCALL RDBYT ;读数据MOV @R0,ADJNZ NB,ACK ;判断是否读到最后一个字节,如果是发出非应答 LCALL MNACK ;信号,如果不是发出应答信号,继续读数据LCALL STOPRETACK: LCALL MACKINC R0SJMP RDN1;*******************************************************************;*并行总线P1.7,P1.6模拟IIC总线软件包 P1.7--SDA, P1.6--SCL * ;*入口:分配以下符号的内存地址: * ;* R0--读写出数据缓冲区首址指针 * ;* SLA--从器件地址存放单元(写地址或地址) * ;* NB--发送(读或写)数据字节数存放单元 * ;*出口:发送N个字节调用WRNBYT,接受N个字节调用RDNBYT,发送N * ;* 个字节但不要STOP调用WRNBYTS * ;*占用资源:F0标志位,C,R0,R1(第三组) * ;******************************************************************** STA:SETB SDA ;发启始位SETB SCLNOPNOPNOPNOPCLR SDANOPNOPNOPNOPCLR SCLRETSTOP: ;发停止位CLR SDASETB SCLNOPNOPNOPNOPNOPSETB SDANOPNOPNOPNOPCLR SCLRETMACK: ;发应答位CLR SDASETB SCLNOPNOPNOPNOPCLR SCLSETB SDARETMNACK: ;发非应答位SETB SDASETB SCLNOPNOPNOPNOPCLR SCLCLR SDARETCACK: ;发非应答位SETB SDASETB SCLCLR F0MOV A,P1JNB ACC.7,CEND ;应答位为1,不置位F0 SETB F0CEND: CLR SCLNOPRETWRBYT: ;写单字节MOV R1,#08HWLP: RLC AJC WR1AJMP WR0 ;跳入写0WLP1: DJNZ R1,WLPRETWR1: ;写1SETB SDASETB SCLNOPNOPNOPNOPCLR SCLCLR SDAAJMP WLP1WR0: ;写0CLR SDASETB SCLNOPNOPNOPNOPCLR SCLAJMP WLP1RDBYT: ;读单字节MOV R1,#08HRLP:SETB SDASETB SCLMOV A,P1JNB ACC.7,RD0 ;转读0AJMP RD1 ;转读1RLP1:DJNZ R1,RLP ;8位全接收完毕,转退出 RETRD0:CLR CMOV A,R2RLC AMOV R2,ACLR SCLAJMP RLP1RD1:SETB CMOV A,R2RLC AMOV R2,ACLR SCLAJMP RLP1END。
本程序是HCS系列都可以本人已通过实验下面是程序代码/*****************头文件*****************************************/#include <hidef.h> /* for EnableInterrupts macro */#include "derivative.h" /* include peripheral declarations */#include "iic24c02.h"/*********************延时函数************************************/ void delay(void){byte i;i=8;while(i>0){i--;}}/*********************ICC初始化************************************/ void Init_IIC(void){SOPT1_IICPS=0; //IIC 在PTA引脚上// IICF=0x0d; //设置波特率<100kbps// IICF=0X4B;IICF=0X24;IICC_IICEN=1;//使能IICIICC_TXAK=0; //当接收完一字节数据产生确认位IICC_IICIE=0;//禁止中断// IICA=0x38;}/*********************写函数************************************/void WRITE_IIC(uchar addres,uchar date){byte temp;IICC_IICEN = 0;IICC_IICEN = 1; //使能IICtemp = IICS; //清中断IICS_IICIF = 1;IICC_MST=0;IICS_SRW=0;IICC_TX=1; //写使能IICC_MST=1; //设为主模式delay();IICD=0xA0; //发送芯片地址,写命令while(!IICS_IICIF );temp = IICS;IICS_IICIF=1;IICD=addres; //发送寄存器地址while(!IICS_IICIF);temp = IICS;IICS_IICIF=1;IICD=date;//写第1个字节while(!IICS_IICIF);temp = IICS;IICS_IICIF=1;IICC1_TX=0;IICS_SRW=0;IICC1_MST=0;}/*********************读一个字节************************************/byte IIC_read_one_byte(byte address){byte temp;IICC_RSTA=0;IICC_IICEN = 0;IICC_IICEN = 1; //使能IICtemp = IICS; /* Clear any pending interrupt */IICS_IICIF = 1;IICC1_MST=0;IICS_SRW=0;IICC_TX=1; //写使能IICC_MST=1; //置为主模式delay();IICD=0xA0; //发送芯片地址,写命令while(!IICS_IICIF);temp = IICS;IICS_IICIF=1;IICD=address; //发送寄存器地址while(!IICS_IICIF);temp = IICS;IICS_IICIF=1;IICC_TXAK=1;IICC_RSTA=1; //重新启动IICD=0xA1; //读命令while(!IICS_IICIF);temp = IICS;IICS_IICIF=1;IICC_TX=0; //读使能temp=IICD;while(!IICS_IICIF);temp = IICS;IICS_IICIF=1;temp=IICD; //读一个字节IICC_MST=0;delay();return(temp);}。
本文档内容为在STM32条件下的24C02读写程序。
全文共分四部分,第一部分24C02的C程序,第二部分为24C02的.h程序,第三部分为端口与时钟配置函数,第四部分为主函数。
下面分别进行介绍。
第一部分:24C02的.c函数******************************************************************************/ #include "stm32f10x.h"#include "system_config.h"#include "24C02.h"u8 savedata[10]={10,9,8,7,6,5,4,3,2,1};/****************************************************************************** ** Function Name : AT24C02_SDA_IO_SET(uchar io_set)* Description : SDA方向控制* Input : None* Output : None* Return : None******************************************************************************* /void AT24C02_SDA_IO_SET(unsigned char io_set){GPIO_InitTypeDef GPIO_InitStructure;if(io_set){GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 ;//SDA 设置为输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOB, &GPIO_InitStructure);}else{GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 ;//SDA 设置为输入GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOB, &GPIO_InitStructure);}}/****************************************************************************** ** Function Name : delay2* Description : 延时函数* Input : None* Output : None* Return : None******************************************************************************* /void delay2(u8 x){u8 i;for(i=0;i<x;i++);}/****************************************************************************** ** Function Name : delay2* Description : 延时函数* Input : None* Output : None* Return : None******************************************************************************* /void delay_nop(void){uint8_t i=10;//延时1.5uswhile(i--);}/****************************************************************************** ** Function Name : 24C02_init()* Description : 初始化函数* Input : None* Output : None* Return : None******************************************************************************* /void I2C_init(void){//SCL=1SCL_H;delay_nop();//SDA=1SDA_H;delay_nop();}/****************************************************************************** ** Function Name : I2C_start()* Description : 开始信号* Input : None* Output : None* Return : None******************************************************************************* /void I2C_start(){SDA_H;delay_nop();SCL_H;delay_nop();SDA_L;delay_nop();SCL_L;delay_nop();}/****************************************************************************** ** Function Name : I2C_stop()* Description : 开始信号* Input : None* Output : None* Return : None******************************************************************************* /void I2C_stop(){SDA_L;delay_nop();SCL_H;delay_nop();SDA_H;delay_nop();}/****************************************************************************** ** Function Name : I2C_write_bit()* Description : 开始信号* Input : None* Output : None* Return : None******************************************************************************* /void I2C_write_bit(int j){int i,temp,temp1;temp=j;//AT24C02_SDA_IO_SET(1);//发送数据for(i=0;i<8;i++){temp1=temp&0x80;//高位在前相与temp=temp<<1;SCL_L;//时钟线设为低delay_nop();if(temp1==0x80)//发送数据到SDA线上{SDA_H;delay_nop();}else{SDA_L;delay_nop();}SCL_H;//时钟线设为高,开始传输数据delay_nop();}SCL_L;//一个字节发送完成delay_nop();SDA_H;delay_nop();}/****************************************************************************** ** Function Name : I2C_read_bit()* Description : 读取一个字节数据* Input : None* Output : None* Return : None******************************************************************************* /u8 I2C_read_bit(){u8 i,j,k=0;SCL_L;delay_nop();SDA_H;delay_nop();A T24C02_SDA_IO_SET(0);//SDA设置为输入for(i=0;i<8;i++){delay_nop();SCL_H;delay_nop();if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)==1)j=1;elsej=0;k=(k<<1)|j;SCL_L;delay_nop();}A T24C02_SDA_IO_SET(1);//SDA设置为输出delay_nop();return(k);}/****************************************************************************** ** Function Name : I2C_reply()* Description : 读取应答信号* Input : None* Output : None* Return : None******************************************************************************* /void I2C_reply(){u16 i=0;A T24C02_SDA_IO_SET(0);//SDA设置为输入SCL_H;delay_nop();while((GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)==1)&&(i<5000))i++;SCL_L;delay_nop();A T24C02_SDA_IO_SET(1);//SDA设置为输出}/****************************************************************************** ** Function Name : I2C_write_addr()* Description : 指定地址写* Input : None* Output : None* Return : None******************************************************************************* /void I2C_write_addr(u8 addr,u8 data){I2C_start();//开始信号I2C_write_bit(0xa0);//发送写命令I2C_reply();//等待应答I2C_write_bit(addr);//发送写地址I2C_reply();//等待应答I2C_write_bit(data);//发送写数据I2C_reply();//等待应答I2C_stop();//停止信号delay2(250);}/****************************************************************************** ** Function Name : I2C_read_addr()* Description : 指定地址读* Input : None* Output : None* Return : None******************************************************************************* /int I2C_read_addr(int addr){int i=0;I2C_start();//开始信号I2C_write_bit(0xa0);//发送写命令因为要先写入要读的地址I2C_reply();//等待应答I2C_write_bit(addr);//发送读地址I2C_reply();//等待应答I2C_start();//开始信号I2C_write_bit(0xa1);//发送读命令I2C_reply();//等待应答i=I2C_read_bit();I2C_stop();//停止信号delay2(250);return(i);}第二部分:24C02的.h函数#define SCL_H GPIO_SetBits(GPIOB,GPIO_Pin_6)#define SCL_L GPIO_ResetBits(GPIOB,GPIO_Pin_6)#define SDA_H GPIO_SetBits(GPIOB,GPIO_Pin_7)#define SDA_L GPIO_ResetBits(GPIOB,GPIO_Pin_7)#define Write_able GPIO_ResetBits(GPIOB,GPIO_Pin_5)//24C02写使能控制引脚void AT24C02_SDA_IO_SET(unsigned char io_set);void delay2(u8 x) ;void delay_nop(void);void I2C_init(void);void I2C_start();void I2C_stop();void I2C_write_bit(int j);u8 I2C_read_bit();void I2C_reply();void I2C_write_addr(u8 addr,u8 data) ;int I2C_read_addr(int addr) ;第三部分:端口与时钟配置函数由于我们使用的是PB6作为时钟线,PB7作为数据线,所以端口配置PB6,PB7就可以了。
4.软件模拟IIC通信(stm32为例)1. 硬件连接1.1 从设备端引脚连接1.2 mcu端引脚连接2. iic初始化1 #include "delay.h"23#define IIC_SCL PBout(8) //SCL(输出)4#define IIC_SDA PBout(9) //SDA(输出)5#define IIC_SDA_R PBin(9) //SDA(输⼊)67void AT24C0X_IIC_Init(void)8 {9 GPIO_InitTypeDef GPIO_InitStructure;1011 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能gpiob时钟12 //GPIOB8,B9初始化13 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;14 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //普通输出模式15 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出,增加输出电流能⼒16 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz,⾼速响应17 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //使能上拉电阻18 GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化gpio19 PBout(8)=1; // iic_scl,时序图初始为⾼电平20 PBout(9)=1; // iic_sda,时序图初始为⾼电平21 }22void sda_pin_mode(GPIOMode_TypeDef mode) // GPIO_Mode_IN,GPIO_Mode_OUT23 {24 GPIO_InitTypeDef GPIO_InitStructure;2526 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能gpiob时钟27 //GPIOB8,B9初始化28 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;29 GPIO_InitStructure.GPIO_Mode = mode; //普通输⼊或出模式30 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出,增加输出电流能⼒31 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz,⾼速响应32 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //使能上拉电阻33 GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化gpio34 }3.时序图3.1 开始和终⽌的定义(Start and Stop Definition)3.1.1 开始信号1void iic_start(void)2 {3//保证sda引脚为输出模式4 sda_pin_mode(GPIO_Mode_OUT);56 IIC_SCL = 1; // 1.初始电平都为⾼电平7 IIC_SDA = 1;8 delay_us(5); // 延时5us,保证电平稳定有效910 IIC_SDA = 0; // 2.scl为⾼期间,sda:1->011 delay_us(5); // 产⽣start信号1213 IIC_SCL = 0; // 3.钳住iic总线,准备开始发送数据14 delay_us(5); //15 }3.1.2 终⽌信号(停⽌信号)void iic_stop(void){//保证sda引脚为输出模式sda_pin_mode(GPIO_Mode_OUT);IIC_SCL = 1; // 1.初始电平为⾼电平IIC_SDA = 0; // 初始电平为低电平delay_us(5);IIC_SDA = 1; // 2.scl为⾼期间,sda:0->1delay_us(5);}3.2 输出应答(Data Validity)3.2.1 从机应答(主机等待从机应答)1 uint8_t iic_wait_ack(void)2 {3 uint8_t ack = 0;45//保证sda引脚为输出模式6 sda_pin_mode(GPIO_Mode_IN);7 IIC_SCL = 1; // 在scl=1期间,读取sda8 delay_us(5);910if(IIC_SDA_R)11 {12 ack = 1; // 若sda_r为1,则⽆应答13 }14else15 {16 ack = 0; // 若sda_r为0,则有应答17 }18return ack;19 }3.2.2 主机应答void iic_ack(void){//保证sda引脚为输出模式sda_pin_mode(GPIO_Mode_OUT);IIC_SCL = 0; // scl初始电平IIC_SDA = 0; // sda初始电平delay_us(5);IIC_SCL = 1; // scl=1期间,delay_us(5);IIC_SDA = 0; // sda=0,主机应答}3.2.3 主机不应答1void iic_no_ack(void)2 {3//保证sda引脚为输出模式4 sda_pin_mode(GPIO_Mode_OUT);56 IIC_SCL = 0; // scl初始电平7 IIC_SDA = 1; // sda初始电平8 delay_us(5);910 IIC_SCL = 1; // scl=1期间,11 delay_us(5);1213 IIC_SDA = 1; // sda=1,主机不应答14 }3.3 读写时序3.3.1 数据有效性(Data Validity)3.3.2 设备地址(Device Address)3.3.3 写操作1void iic_write_byte(uint8_t byte)2 {3 int32_t i;4//保证sda引脚为输出模式5 sda_pin_mode(GPIO_Mode_OUT);67 IIC_SCL = 0;8 delay_us(5);910for (i=7; i>=0; i--)11 {12if (byte & (1<<i)) // 只有scl=1时才能写数据,bit流由⾼到低13 {14 IIC_SDA = 1;15 }16else17 {18 IIC_SDA = 0;19 }20 delay_us(5);2122 IIC_SCL = 1; //23 delay_us(5);2425 IIC_SCL = 0; // 为下⼀次写数据做准备26 delay_us(5);27 }28 }3.3.4 读操作1 uint8_t iic_read_byte(void)2 {3 uint8_t byte;4 int32_t i;56//保证sda引脚为输出模式7 sda_pin_mode(GPIO_Mode_IN);89 IIC_SCL = 0; // 初始化为低电平10 delay_us(5);1112for (i=7; i>=0; i--)13 {14 IIC_SCL = 1; // 只有在scl=1时,才可以读数据15 delay_us(5);1617if (IIC_SDA_R)18 {19byte |= 1<<i;20 }21else22 {23byte |= 0<<i;24 }25 IIC_SCL = 0; // 为读下⼀个字节的数据做准备26 delay_us(5);27 }28return byte;29 }3.4 向AT24CXX写数据3.4.1 写⼀字节数据( Byte Write)1 uint32_t AT24CXX_Byte_Write(uint8_t addr,uint8_t byte)2 {3 uint8_t ack;45// 1.发送开始信号6 iic_start();78// 2.写设备地址,选择iic总线的设备,bit流由⾼到低(从最⾼位开始写) 9 iic_write_byte(0xA0);1011// 3.等待从机应答(从机位EEPROM设备,主机位mcu设备)12 ack = iic_wait_ack();13if (1 == ack)14 {15 printf("dev addr is error!\r\n");16return -1;17 }1819// 4.写⼊数据地址(数据在eeprom中要存放的位置)20 iic_write_byte(addr);2122// 5.等待从机应答23 ack = iic_wait_ack();24if (1 == ack)25 {26 printf("data addr is error!\r\n");27return -2;28 }2930// 6.写⼊要存⼊EEPROM中的数据31 iic_write_byte(byte);3233// 7.等到从机应答34 ack = iic_wait_ack();35if (1 == ack)36 {37 printf("data addr is error!\r\n");38return -3;39 }4041// 8.发送终⽌信号42 iic_stop();4344return0;45 }3.4.2 写⼀页的数据(Page Write)1 int32_t AT24C0X_Page_Write(uint8_t addr,uint8_t *pbuf,uint8_t len)2 {3 uint8_t ack;4 uint8_t i;56// 1.发送起始信号7 iic_start();89// 2.发送设备地址,iic总线寻址10 iic_write_byte(0xA0); // 写设备地址(0xA0)1112 // 3.等待应答信号13 ack = iic_wait_ack();14if (ack)15 {16 printf("dev addr is err!\r\n");17return -1;18 }1920// 4.发送要写⼊的数据地址21 iic_write_byte(addr);2223// 5.等待应答信号24 ack = iic_wait_ack();25if (ack)26 {27 printf("data addr is err!\r\n");28return -2;29 }3031// 6.发送要写⼊的数据(多字节)32for (i=0; i<len; i++)33 {34// 发送要写⼊的数据35 iic_write_byte(pbuf[i]);36// 等待应答37 ack = iic_wait_ack();38if (ack)39 {40 printf("data is err!\r\n");41return -3;42 }43 }44// 7.发送停⽌信号45 iic_stop();46 }3.4.3 写⼊多字节的数据(写⼊数据流)1 int32_t AT24CXX_Write_Data(uint8_t Addr,uint8_t *pBuf,uint16_t Len)2 {3while(Len--)4 {5 AT24CXX_Byte_Write(Addr,pBuf);6 Addr++; // ⽬的地址(eeprom中存储数据的地址+1)7 pBuf++; // 源地址(源数据的地址)8 }9return0;10 }3.5 从AT24CXX读数据3.5.1 任意地址读⼀个byte(Random Read)1 uint8_t AT24CXX_Read_Byte_Random(uint8_t addr)2 {3 uint8_t byte;4 uint8_t ack;56// 1.发送开始信号7 iic_start();89// 2.写⼊要读的设备地址(硬件设备id),为写⽅向10 iic_write_byte(0xA0);1112// 3.等待从机应答信号13 ack = iic_wait_ack();14if (ack)15 {16 printf("When Master read randomly,what write slave device address is error! r\n"); 17return -1;18 }1920// 4.写⼊从机设备(eeprom)中,要读的位置21 iic_write_byte(addr);2223// 5.等待从机应答信号24 ack = iic_wait_ack();25if (ack)26 {27 printf("When Master read randomly,what write data address in slave is error! r\n"); 28return -2;29 }3031// 6.发送开始信号32 iic_start();3334// 7.写⼊要读的设备地址(硬件设备id),为读⽅向35 iic_write_byte(0xA1);3637// 8.等待从机应答信号38 ack = iic_wait_ack();39if (ack)40 {41 printf("When Master read randomly,what write data address in slave is error! r\n"); 42return -2;43 }4445// 9.读取从机数据(eeprom)46byte = iic_read_byte();4748// 10.主机不应答49 iic_no_ack();5051// 11.发送停⽌信号52 iic_stop();5354return byte;55 }3.5.2 读出short或int型的数据1/**2 * @brief 在AT24XX⾥⾯的指定地址开始读出长度为Len的数据,该函数⽤于读出3 * 读出16bit或者32bit的数据4 * @param ReadAddr:开始读出的地址5 * @param Len:读出数据的长度2,46 *7 * @retval 数据8 */9 uint32_t AT24CXX_ReadLenByte(uint16_t ReadAddr,uint8_t Len)10 {11 uint8_t t;12 uint32_t temp=0;13for(t=0;t<Len;t++)14 {15 temp<<=8;16 temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1); //17 }18return temp;19 }3.5.3 读出epprom中⼀定长度的数据1/**2 * @brief 在AT24XX⾥⾯的指定地址开始读出指定长度为Len的数据3 * @param ReadAddr:开始读出的地址,对24c02为0-2554 * @param pData:输出数据数组⾸地址5 * @param Len:要读数据的个数67 */8void AT24CXX_Read_Data(uint16_t addr,uint8_t *pData, uint16_t DataLen)9 {10while (DataLen--)11 {12 *pData++ = AT24CXX_Read_Byte_Random(addr++);13 }14 }。
1. AT24C02写操作首先我们来看一下写AT24C02。
一般步骤是:1) 发送起始信号2) 发送写器件地址3) 等待应答4) 发送要写入的24C02 的地址5) 等待应答6) 发送要写入的数据7) 等待应答8) 发送数据结束发送结束信号具体程序如下:/****************************************************************************** ** 函数名: AT24Cxx_WriteOneByte* 函数功能: 24c02写一个字节地址数据* 输入: addr dt* 输出: 无********************************************/void AT24Cxx_WriteOneByte(u16 addr,u8 dt){I2C_Start();if(EE_TYPE>AT24C16){I2C_Send_Byte(0xA0);I2C_Wait_Ack();I2C_Send_Byte(addr>>8); //发送数据地址高位}else{I2C_Send_Byte(0xA0+((addr/256)<<1));//器件地址+数据地址}I2C_Wait_Ack();I2C_Send_Byte(addr%256);//双字节是数据地址低位//单字节是数据地址低位I2C_Wait_Ack();I2C_Send_Byte(dt);I2C_Wait_Ack();I2C_Stop();delay_ms(10);}2. AT24C02读操作那么读取AT24C02 的步骤是:1)发送起始信号2) 发送写器件地址3) 等待应答4) 发送要读取的AT24C02 的地址5) 等待应答6) 再发送其实信号7) 发送读器件地址8) 等待应答9) 接收数据10) 如果没有接收完数据,发送应答11) 接收数据12) 直到接收完数据,发送非应答13) 发送结束信号/****************************************************************************** ** 函数名: AT24Cxx_ReadOneByte* 函数功能: 24c02读一个字节地址数据* 输入: addr* 输出: 返回值temp*****************************************************************************/ u8 AT24Cxx_ReadOneByte(u16 addr){u8 temp=0;I2C_Start();if(EE_TYPE>AT24C16){I2C_Send_Byte(0xA0);I2C_Wait_Ack();I2C_Send_Byte(addr>>8); //发送数据地址高位}else{I2C_Send_Byte(0xA0+((addr/256)<<1));//器件地址+数据地址}I2C_Wait_Ack();I2C_Send_Byte(addr%256);//双字节是数据地址低位//单字节是数据地址低位I2C_Wait_Ack();I2C_Start();I2C_Send_Byte(0xA1);I2C_Wait_Ack();temp=I2C_Read_Byte(0); // 0 代表NAC I2C_NAck();I2C_Stop();return temp;}。
STM32模拟IIC读写24C02程序代码STM32 模拟IIC读写24C02程序代码最近用到STM32F103V来读写A T24C02 EEPROM 于是从原来51单片机的程序代码的基础上修改了下,移植到了STM32,测试工作正常。
引脚定义和配置:#define SCL GPIO_Pin_6 //24C02 SCL#define SDA GPIO_Pin_7 //24C02 SDAvoid GPIO_Configuration(void){RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1 |RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD |RCC_APB2Periph_GPIOE, ENABLE);GPIO_InitStructure.GPIO_Pin = SCL; //24C02 SC LGPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = SDA; //24C02 SDA 作为输出GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);}void AT24C02_SDA_IO_SET(unsigned char io_set) //SDA引脚输入输出设置{if(io_set==0){GPIO_InitStructure.GPIO_Pin = SDA; //24C02 SDA 作为输出GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);else if(io_set==1){GPIO_InitStructure.GPIO_Pin = SDA; //24C02 SDA 作为输入GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入GPIO_Init(GPIOB, &GPIO_InitStructure);}else{;}}////////////////////////////////////主程序////////////////////////////////////////////////////////////////////// ////////int main(void){ uchar i;uchar data_24c02;RCC_Configuration(); //时钟配置GPIO_Configuration();//GPIO配置USARTx_configuration();//串口配置WIN24C02_init();delayms(5000);//延时for(i=0;i<20;i++) //写EEPROM数据{ WIN24C02_write(0x00+i,i);delayms(100);}//存数据到EEPROMdelayms(1000);//延时while(1)//串口3发送读取的EEPROM的数据{for(i=0;i<20;i++){ data_24c02=WIN24C02_read(0x00+i);//读取24C02数据USART_SendData(USART3 ,data_24c02);while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET);}delayms(5000);//延时}/////////////////////////////////////////////////////////////////// //////////////////////////////////////////////WIN_24C02.H头文件/**********************中文版本*******************************//*****功能描述: STM32 24C02 读写程序*****//*****作者: 郑文(ClimberWin) *****//*****编写日期: 2013年1月21日*****//*****版本信息: V1.0 *****//*****修改日期: *****//*************************************************************/ #ifndef __WIN24C02_H__#define __WIN24C02_H__#include"STM32_Config.h"#define uchar unsigned char#define uint unsigned intuchar WIN24C02_read(uchar address); //从24c02的地址address中读取一个字节数据void WIN24C02_write(uchar address,uchar info); //向24c02的address地址中写入一字节数据infovoid WIN24C02_init(); //24c02初始化子程序void delay_nop(void);void delay2(uint x);void start();void stop();void writex(uchar j);uchar readx();void clock();void delay2(uint x){uint i;for(i=0;i<x;i++);< p="">}void delay_nop(void){uint8_t i=10; //i=10延时1.5us//这里可以优化速度,经测试最低到5还能写入while(i--);}void WIN24C02_init(){//SCL=1;GPIO_SetBits(GPIOB,SCL);delay_nop();//SDA=1;GPIO_SetBits(GPIOB,SDA);delay_nop();}void start(){//SDA=1;GPIO_SetBits(GPIOB,SDA);delay_nop();//SCL=1;GPIO_SetBits(GPIOB,SCL); delay_nop();//SDA=0;GPIO_ResetBits(GPIOB, SDA); delay_nop();//SCL=0;GPIO_ResetBits(GPIOB, SCL); delay_nop();}void stop(){//SDA=0;GPIO_ResetBits(GPIOB, SDA); delay_nop();//SCL=1;GPIO_SetBits(GPIOB,SCL); delay_nop();//SDA=1;GPIO_SetBits(GPIOB,SDA); delay_nop();}void writex(uchar j){uchar i,temp,temp1;temp=j;//A T24C02_SDA_IO_SET(0); for (i=0;i<8;i++){temp1=temp & 0x80;temp=temp<<1;//SCL=0;GPIO_ResetBits(GPIOB, SCL);delay_nop();//SDA=CY;if(temp1==0x80){GPIO_SetBits(GPIOB, SDA);} else {GPIO_ResetBits(GPIOB, SDA);} delay_nop(); // SCL=1;GPIO_SetBits(GPIOB,SCL);delay_nop();}//A T24C02_SDA_IO_SET(0);//SCL=0;GPIO_ResetBits(GPIOB, SCL);delay_nop();//SDA=1;GPIO_SetBits(GPIOB,SDA);delay_nop();}uchar readx(){uchar i,j,k=0;//SCL=0;GPIO_ResetBits(GPIOB, SCL);delay_nop();//SDA=1;GPIO_SetBits(GPIOB,SDA);AT24C02_SDA_IO_SET(1);for (i=0;i<8;i++){delay_nop();//SCL=1;GPIO_SetBits(GPIOB,SCL);delay_nop();//if (SDA==1) j=1;if( GPIO_ReadInputDataBit(GPIOB,SDA)==1 ) {j=1;}else{j=0;}k=(k<<1)|j;//SCL=0;GPIO_ResetBits(GPIOB, SCL);}AT24C02_SDA_IO_SET(0);delay_nop();return(k);}{uint i=0;AT24C02_SDA_IO_SET(1);//SCL=1;GPIO_SetBits(GPIOB,SCL);delay_nop();while((GPIO_ReadInputDataBit(GPIOB,SDA)==1)&&(i<5000))i++;//SCL=0;GPIO_ResetBits(GPIOB, SCL);delay_nop();AT24C02_SDA_IO_SET(0);}uchar WIN24C02_read(uchar address){uchar i;start();writex(0xa0);clock();writex(address);clock();start();writex(0xa1);clock();i=readx();stop();//delay2(10);delay2(50);return(i);}void WIN24C02_write(uchar address,uchar info) {start();writex(0xa0);clock();writex(address);writex(info);clock();stop();//delay2(50);delay2(250); }#endif</x;i++);<>。