完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
STM32 使用IO口模拟IIC读写AT24C128
AT24C128简介 AT24C128,ATMEL公司出的EEPROM芯片,共有16,384 x 8bit,整个存储器共有256页,每页64BYTES. 使用IIC协议。 使用STM32的IO模拟IIC的时序 头文件 #ifndef EEPROM_H #define EEPROM_H #include "Typedef.h" #define IIC_SDA_PORT GPIOA #define IIC_SCL_PORT GPIOA #define IIC_SCL_PIN GPIO_PIN_3 #define IIC_SDA_PIN GPIO_PIN_4 #define HIGH GPIO_PIN_SET #define LOW GPIO_PIN_RESET #define PinInput 1 #define PinOutput 0 #define SDA_IN() {GPIOA->CRL&=0XFFF0FFFF;GPIOA->CRL|=(u32)8<<16;} #define SDA_OUT() {GPIOA->CRL&=0XFFF0FFFF;GPIOA->CRL|=(u32)3<<16;} #define GetSDA() (HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4)==GPIO_PIN_SET) //(GPIOA->IDR&((u32)1<<4)) #define SetSDA(state) HAL_GPIO_WritePin(IIC_SDA_PORT,IIC_SDA_PIN,state) #define SetSCL(state) HAL_GPIO_WritePin(IIC_SCL_PORT,IIC_SCL_PIN,state) #define E_DELAY 2 // 两个EEPROM命令之间的间隔 extern u8 iic_cmd_delay; extern u8 AT24CXX_ReadOneByte(u32 ReadAddr); extern void AT24CXX_WriteOneByte(u32 WriteAddr,u8 DataToWrite); extern void AT24CXX_Read(u32 ReadAddr,u8 *pBuffer,u16 NumToRead); extern void AT24CXX_Write(u32 WriteAddr,u8 *pBuffer,u16 NumToWrite); extern void AT24CXX_clr(u32 WriteAddr,u32 NumToWrite); extern void IIC_Start1(void); void IIC_Stop(void); u8 IIC_Wait_Ack(void); void IIC_Ack(void); void IIC_NAck(void); void IIC_Send_Byte(u8 txd); void delay_nop(void); void SetSDADirection(u8 direction); #endif c文件 #include "main.h" #include "eeprom.h" /* AT24C128C organized as 256 pages of 64-bytes each AT24C512C, organized as 512 pages of 128 bytes each 不同的的EEPROM对应的页大小不一样,注意修改 */ #define PAGE_SIZE 64 u8 iic_cmd_delay=0; void SetSDADirection(u8 direction) { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = IIC_SDA_PIN; if(direction) { GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; } else { GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; } HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } // SDA /***********************iic**************************/ void delay_nop(void) { unsigned int i; for(i=0;i<50;i++) __nop(); } //产生IIC起始信号 void IIC_Start(void) { /*while(iic_cmd_delay < E_DELAY) // 距上一个命令时间太短 { R_WDT_Restart(); }*/ SDA_OUT();//sda线输出 SetSDA(HIGH); SetSCL(HIGH); delay_nop(); SetSDA(LOW);//START:when CLK is high,DATA change form high to low delay_nop(); SetSCL(LOW);//钳住I2C总线,准备发送或接收数据 } void IIC_Start1(void) { SDA_OUT(); //sda线输出 SetSDA(HIGH); delay_nop(); SetSCL(HIGH); delay_nop(); SetSDA(LOW); //START:when CLK is high,DATA change form high to low delay_nop(); SetSCL(LOW); //钳住I2C总线,准备发送或接收数据 } //产生IIC停止信号 void IIC_Stop(void) { SetSDA(LOW); SDA_OUT();//sda线输出 SetSCL(LOW); delay_nop(); SetSCL(HIGH); delay_nop(); SetSDA(HIGH);//发送I2C总线结束信号 delay_nop(); iic_cmd_delay=0; } //等待应答信号到来 //返回值: // 1,接收应答失败 // 0,接收应答成功 u8 IIC_Wait_Ack(void) { u8 flag; SDA_IN(); //SDA设置为输入 SetSDA(HIGH); delay_nop(); SetSCL(HIGH); delay_nop(); if(GetSDA()) flag=1; else flag=0; SetSCL(LOW); //时钟输出0 return flag; } //产生ACK应答 void IIC_Ack(void) { SetSCL(LOW); SDA_OUT(); SetSDA(LOW); delay_nop(); SetSCL(HIGH); delay_nop(); SetSCL(LOW); } //不产生ACK应答 void IIC_NAck(void) { SetSCL(LOW); SDA_OUT(); SetSDA(HIGH); delay_nop(); SetSCL(HIGH); delay_nop(); SetSCL(LOW); } //IIC发送一个字节 //返回从机有无应答 //1,有应答 //0,无应答 void IIC_Send_Byte(u8 txd) { u8 t; SDA_OUT(); SetSCL(LOW);//拉低时钟开始数据传输 for(t=0;t<8;t++) { if((txd&0x80)>>7) SetSDA(HIGH); else SetSDA(LOW); txd<<=1; delay_nop(); SetSCL(HIGH); delay_nop(); SetSCL(LOW); } } //读1个字节,ack=1时,发送ACK,ack=0,发送nACK u8 IIC_Read_Byte(u8 ack) { u8 i,receive=0; SDA_IN(); for(i=0;i<8;i++ ) { SetSCL(LOW); delay_nop(); SetSCL(HIGH); delay_nop(); receive<<=1; if(GetSDA()) receive++; } if (!ack) IIC_NAck();//发送nACK else IIC_Ack(); //发送ACK return receive; } /***********************iic**************************/ //在AT24CXX指定地址读出一个数据 //ReadAddr:开始读数的地址 //返回值 :读到的数据 u8 AT24CXX_ReadOneByte(u32 ReadAddr) { u8 temp; u8 addrH,addrL; addrH=ReadAddr>>8; addrL=ReadAddr&0xff; IIC_Start(); IIC_Send_Byte(0xa0); IIC_Wait_Ack(); IIC_Send_Byte(addrH); //发送高地址 IIC_Wait_Ack(); IIC_Send_Byte(addrL); //发送低地址 IIC_Wait_Ack(); IIC_Start(); IIC_Send_Byte(0xa1); //进入接收模式 IIC_Wait_Ack(); temp= IIC_Read_Byte(0); IIC_Stop();//产生一个停止条件 return temp; } //在AT24CXX指定地址写入一个数据 //WriteAddr :写入数据的目的地址 //DataToWrite:要写入的数据 void AT24CXX_WriteOneByte(u32 WriteAddr,u8 DataToWrite) { u8 addrH,addrL; addrH=WriteAddr>>8; addrL=WriteAddr&0xff; IIC_Start(); IIC_Send_Byte(0xa0); IIC_Wait_Ack(); IIC_Send_Byte(addrH); //发送高地址 IIC_Wait_Ack(); IIC_Send_Byte(addrL); //发送低地址 IIC_Wait_Ack(); IIC_Send_Byte(DataToWrite); //发送字节 IIC_Wait_Ack(); IIC_Stop();//产生一个停止条件 } //在AT24CXX里面的指定地址开始读出指定个数的数据 //ReadAddr :开始读出的地址 对24c02为0~255 //pBuffer :数据数组首地址 //NumToRead:要读出数据的个数 void AT24CXX_Read(u32 ReadAddr,u8 *pBuffer,u16 NumToRead) { u8 addrH,addrL; if(NumToRead==0) return; addrH=ReadAddr>>8; addrL=ReadAddr&0xff; IIC_Start(); IIC_Send_Byte(0xa0);//写 IIC_Wait_Ack(); IIC_Send_Byte(addrH); //发送高地址 IIC_Wait_Ack(); IIC_Send_Byte(addrL); //发送低地址 IIC_Wait_Ack(); IIC_Start(); IIC_Send_Byte(0xa1); //读 //进入接收模式 IIC_Wait_Ack(); NumToRead--; while(NumToRead) { *pBuffer=IIC_Read_Byte(1); pBuffer++; ReadAddr++; NumToRead--; } *pBuffer=IIC_Read_Byte(0); IIC_Stop();//产生一个停止条件 } //在AT24CXX里面的指定地址开始写入指定个数的数据 //WriteAddr :开始写入的地址 对24c02为0~255 //pBuffer :数据数组首地址 //NumToWrite:要写入数据的个数 // 每128bytes为一个page,写操作不能跨页 void AT24CXX_Write(u32 WriteAddr,u8 *pBuffer,u16 NumToWrite) { u8 addrH,addrL; u16 lentmp,lentow,lens; u8 tmp; if(NumToWrite==0) return; lentmp=NumToWrite; while(lentmp) { tmp=WriteAddr%PAGE_SIZE; tmp=PAGE_SIZE-tmp; if(tmp>=lentmp)//当页剩余空间大于要写入的长度 { lentow=lentmp; } else { lentow=tmp;//写入长度只能是剩余空间长度 } lentmp=lentmp-lentow;//计算要在下一页写入的长度 lens=lentow; addrH=WriteAddr>>8; addrL=WriteAddr&0xff; IIC_Start(); IIC_Send_Byte(0xa0); IIC_Wait_Ack(); IIC_Send_Byte(addrH); //发送高地址 IIC_Wait_Ack(); IIC_Send_Byte(addrL); //发送低地址 IIC_Wait_Ack(); while(lentow--) { IIC_Send_Byte(*pBuffer); IIC_Wait_Ack(); pBuffer++; } IIC_Stop();//产生一个停止条件 WriteAddr=WriteAddr+lens;//下一页的地址 } } void AT24CXX_clr(u32 WriteAddr,u32 NumToWrite) { u8 addrH,addrL; u16 lentmp,lentow,lens; u8 tmp; lentmp=NumToWrite; while(lentmp) { tmp=WriteAddr%PAGE_SIZE; tmp=PAGE_SIZE-tmp; if(tmp>=lentmp) { lentow=lentmp; } else { lentow=tmp; } lentmp=lentmp-lentow; lens=lentow; addrH=WriteAddr>>8; addrL=WriteAddr&0xff; IIC_Start(); IIC_Send_Byte(0xa0); IIC_Wait_Ack(); IIC_Send_Byte(addrH); //发送高地址 IIC_Wait_Ack(); IIC_Send_Byte(addrL); //发送低地址 IIC_Wait_Ack(); while(lentow--) { IIC_Send_Byte(0xff); IIC_Wait_Ack(); } IIC_Stop();//产生一个停止条件 WriteAddr=WriteAddr+lens; } } //----------------------EEPROM---------------------------// //--------------------------------------------------------EEPROM DATA PS 扩展内容 本文写的时候是为AT24C128写的,但是也支持其他容量的芯片,比如AT24C02,AT24C256等等。只需要根据对应芯片的页大小修改对应的宏定义就可以了。 |
|
|
|
只有小组成员才能发言,加入小组>>
3309 浏览 9 评论
2988 浏览 16 评论
3490 浏览 1 评论
9050 浏览 16 评论
4085 浏览 18 评论
1171浏览 3评论
602浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
594浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2331浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1894浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-20 12:20 , Processed in 1.197271 second(s), Total 79, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号