完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
本程序取自正点原子开发板,应用于STM32F103单片机,适用AT24C01,AT24C02,AT24C04,AT24C08,AT24C16,AT24C32,AT24C64,AT24C128,AT24C256,AT24C512系列I2C存储芯片。
一、sys.h #ifndef __SYS_H #define __SYS_H #include “stm32f10x.h” // //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //ALIENTEK STM32开发板 //正点原子@ALIENTEK //技术论坛:www.openedv.com //修改日期:2012/8/18 //版本:V1.7 //版权所有,盗版必究。 //Copyright(C) 广州市星翼电子科技有限公司 2009-2019 //All rights reserved // //0,不支持ucos //1,支持ucos #define SYSTEM_SUPPORT_OS 0 //定义系统文件夹是否支持UCOS //位带操作,实现51类似的GPIO控制功能 //具体实现思想,参考《《CM3权威指南》》第五章(87页~92页)。 //IO口操作宏定义 #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)《《5)+(bitnum《《2)) #define MEM_ADDR(addr) *((volatile unsigned long *)(addr)) #define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum)) //IO口地址映射 #define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C #define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C #define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C #define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C #define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C #define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C #define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C #define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808 #define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08 #define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008 #define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408 #define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808 #define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08 #define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08 //IO口操作,只对单一的IO口! //确保n的值小于16! #define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出 #define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入 #define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出 #define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入 #define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出 #define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入 #define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出 #define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入 #define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出 #define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入 #define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出 #define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入 #define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出 #define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入 //以下为汇编函数 void WFI_SET(void); //执行WFI指令 void INTX_DISABLE(void);//关闭所有中断 void INTX_ENABLE(void); //开启所有中断 void MSR_MSP(u32 addr); //设置堆栈地址 #endif 二、sys.c #include “sys.h” // //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //ALIENTEK STM32开发板 //系统中断分组设置化 //正点原子@ALIENTEK //技术论坛:www.openedv.com //修改日期:2012/9/10 //版本:V1.4 //版权所有,盗版必究。 //Copyright(C) 正点原子 2009-2019 //All rights reserved //******************************************************************************** //THUMB指令不支持汇编内联 //采用如下方法实现执行汇编指令WFI void WFI_SET(void) { __ASM volatile(“wfi”); } //关闭所有中断 void INTX_DISABLE(void) { __ASM volatile(“cpsid i”); } //开启所有中断 void INTX_ENABLE(void) { __ASM volatile(“cpsie i”); } //设置栈顶地址 //addr:栈顶地址 __asm void MSR_MSP(u32 addr) { MSR MSP, r0 //set Main Stack value BX r14 } 三、delay.h #ifndef __DELAY_H #define __DELAY_H #include “sys.h” // //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //ALIENTEK STM32开发板 //使用SysTick的普通计数模式对延迟进行管理(适合STM32F10x系列) //包括delay_us,delay_ms //正点原子@ALIENTEK //技术论坛:www.openedv.com //创建日期:2010/1/1 //版本:V1.8 //版权所有,盗版必究。 //Copyright(C) 广州市星翼电子科技有限公司 2009-2019 //All rights reserved //******************************************************************************** //V1.2修改说明 //修正了中断中调用出现死循环的错误 //防止延时不准确,采用do while结构! //V1.3修改说明 //增加了对UCOSII延时的支持。 //如果使用ucosII,delay_init会自动设置SYSTICK的值,使之与ucos的TICKS_PER_SEC对应。 //delay_ms和delay_us也进行了针对ucos的改造。 //delay_us可以在ucos下使用,而且准确度很高,更重要的是没有占用额外的定时器。 //delay_ms在ucos下,可以当成OSTimeDly来用,在未启动ucos时,它采用delay_us实现,从而准确延时 //可以用来初始化外设,在启动了ucos之后delay_ms根据延时的长短,选择OSTimeDly实现或者delay_us实现。 //V1.4修改说明 20110929 //修改了使用ucos,但是ucos未启动的时候,delay_ms中中断无法响应的bug. //V1.5修改说明 20120902 //在delay_us加入ucos上锁,防止由于ucos打断delay_us的执行,可能导致的延时不准。 //V1.6修改说明 20150109 //在delay_ms加入OSLockNesting判断。 //V1.7修改说明 20150319 //修改OS支持方式,以支持任意OS(不限于UCOSII和UCOSIII,理论上任意OS都可以支持) //添加:delay_osrunning/delay_ostickspersec/delay_osintnesting三个宏定义 //添加:delay_osschedlock/delay_osschedunlock/delay_ostimedly三个函数 //V1.8修改说明 20150519 //修正UCOSIII支持时的2个bug: //delay_tickspersec改为:delay_ostickspersec //delay_intnesting改为:delay_osintnesting // void delay_init(void); void delay_ms(u16 nms); void delay_us(u32 nus); #endif 四、delay.c #include “delay.h” // //如果需要使用OS,则包括下面的头文件即可。 #if SYSTEM_SUPPORT_OS #include “includes.h” //ucos 使用 #endif // //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //ALIENTEK STM32开发板 //使用SysTick的普通计数模式对延迟进行管理(适合STM32F10x系列) //包括delay_us,delay_ms //正点原子@ALIENTEK //技术论坛:www.openedv.com //创建日期:2010/1/1 //版本:V1.8 //版权所有,盗版必究。 //Copyright(C) 广州市星翼电子科技有限公司 2009-2019 //All rights reserved //******************************************************************************** //V1.2修改说明 //修正了中断中调用出现死循环的错误 //防止延时不准确,采用do while结构! //V1.3修改说明 //增加了对UCOSII延时的支持。 //如果使用ucosII,delay_init会自动设置SYSTICK的值,使之与ucos的TICKS_PER_SEC对应。 //delay_ms和delay_us也进行了针对ucos的改造。 //delay_us可以在ucos下使用,而且准确度很高,更重要的是没有占用额外的定时器。 //delay_ms在ucos下,可以当成OSTimeDly来用,在未启动ucos时,它采用delay_us实现,从而准确延时 //可以用来初始化外设,在启动了ucos之后delay_ms根据延时的长短,选择OSTimeDly实现或者delay_us实现。 //V1.4修改说明 20110929 //修改了使用ucos,但是ucos未启动的时候,delay_ms中中断无法响应的bug. //V1.5修改说明 20120902 //在delay_us加入ucos上锁,防止由于ucos打断delay_us的执行,可能导致的延时不准。 //V1.6修改说明 20150109 //在delay_ms加入OSLockNesting判断。 //V1.7修改说明 20150319 //修改OS支持方式,以支持任意OS(不限于UCOSII和UCOSIII,理论上任意OS都可以支持) //添加:delay_osrunning/delay_ostickspersec/delay_osintnesting三个宏定义 //添加:delay_osschedlock/delay_osschedunlock/delay_ostimedly三个函数 //V1.8修改说明 20150519 //修正UCOSIII支持时的2个bug: //delay_tickspersec改为:delay_ostickspersec //delay_intnesting改为:delay_osintnesting // static u8 fac_us=0; //us延时倍乘数 static u16 fac_ms=0; //ms延时倍乘数,在ucos下,代表每个节拍的ms数 #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS定义了,说明要支持OS了(不限于UCOS)。 //当delay_us/delay_ms需要支持OS的时候需要三个与OS相关的宏定义和函数来支持 //首先是3个宏定义: // delay_osrunning:用于表示OS当前是否正在运行,以决定是否可以使用相关函数 //delay_ostickspersec:用于表示OS设定的时钟节拍,delay_init将根据这个参数来初始哈systick // delay_osintnesting:用于表示OS中断嵌套级别,因为中断里面不可以调度,delay_ms使用该参数来决定如何运行 //然后是3个函数: // delay_osschedlock:用于锁定OS任务调度,禁止调度 //delay_osschedunlock:用于解锁OS任务调度,重新开启调度 // delay_ostimedly:用于OS延时,可以引起任务调度。 //本例程仅作UCOSII和UCOSIII的支持,其他OS,请自行参考着移植 //支持UCOSII #ifdef OS_CRITICAL_METHOD //OS_CRITICAL_METHOD定义了,说明要支持UCOSII #define delay_osrunning OSRunning //OS是否运行标记,0,不运行;1,在运行 #define delay_ostickspersec OS_TICKS_PER_SEC //OS时钟节拍,即每秒调度次数 #define delay_osintnesting OSIntNesting //中断嵌套级别,即中断嵌套次数 #endif //支持UCOSIII #ifdef CPU_CFG_CRITICAL_METHOD //CPU_CFG_CRITICAL_METHOD定义了,说明要支持UCOSIII #define delay_osrunning OSRunning //OS是否运行标记,0,不运行;1,在运行 #define delay_ostickspersec OSCfg_TickRate_Hz //OS时钟节拍,即每秒调度次数 #define delay_osintnesting OSIntNestingCtr //中断嵌套级别,即中断嵌套次数 #endif //us级延时时,关闭任务调度(防止打断us级延迟) void delay_osschedlock(void) { #ifdef CPU_CFG_CRITICAL_METHOD //使用UCOSIII OS_ERR err; OSSchedLock(&err); //UCOSIII的方式,禁止调度,防止打断us延时 #else //否则UCOSII OSSchedLock(); //UCOSII的方式,禁止调度,防止打断us延时 #endif } //us级延时时,恢复任务调度 void delay_osschedunlock(void) { #ifdef CPU_CFG_CRITICAL_METHOD //使用UCOSIII OS_ERR err; OSSchedUnlock(&err); //UCOSIII的方式,恢复调度 #else //否则UCOSII OSSchedUnlock(); //UCOSII的方式,恢复调度 #endif } //调用OS自带的延时函数延时 //ticks:延时的节拍数 void delay_ostimedly(u32 ticks) { #ifdef CPU_CFG_CRITICAL_METHOD OS_ERR err; OSTimeDly(ticks,OS_OPT_TIME_PERIODIC,&err); //UCOSIII延时采用周期模式 #else OSTimeDly(ticks); //UCOSII延时 #endif } //systick中断服务函数,使用ucos时用到 void SysTick_Handler(void) { if(delay_osrunning==1) //OS开始跑了,才执行正常的调度处理 { OSIntEnter(); //进入中断 OSTimeTick(); //调用ucos的时钟服务程序 OSIntExit(); //触发任务切换软中断 } } #endif //初始化延迟函数 //当使用OS的时候,此函数会初始化OS的时钟节拍 //SYSTICK的时钟固定为HCLK时钟的1/8 //SYSCLK:系统时钟 void delay_init() { #if SYSTEM_SUPPORT_OS //如果需要支持OS. u32 reload; #endif SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK/8 fac_us=SystemCoreClock/8000000; //为系统时钟的1/8 #if SYSTEM_SUPPORT_OS //如果需要支持OS. reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为M reload*=1000000/delay_ostickspersec; //根据delay_ostickspersec设定溢出时间 //reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右 fac_ms=1000/delay_ostickspersec; //代表OS可以延时的最少单位 SysTick-》CTRL|=SysTick_CTRL_TICKINT_Msk; //开启SYSTICK中断 SysTick-》LOAD=reload; //每1/delay_ostickspersec秒中断一次 SysTick-》CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK #else fac_ms=(u16)fac_us*1000; //非OS下,代表每个ms需要的systick时钟数 #endif } #if SYSTEM_SUPPORT_OS //如果需要支持OS. //延时nus //nus为要延时的us数。 void delay_us(u32 nus) { u32 ticks; u32 told,tnow,tcnt=0; u32 reload=SysTick-》LOAD; //LOAD的值 ticks=nus*fac_us; //需要的节拍数 tcnt=0; delay_osschedlock(); //阻止OS调度,防止打断us延时 told=SysTick-》VAL; //刚进入时的计数器值 while(1) { tnow=SysTick-》VAL; if(tnow!=told) { if(tnow《told)tcnt+=told-tnow; //这里注意一下SYSTICK是一个递减的计数器就可以了。 else tcnt+=reload-tnow+told; told=tnow; if(tcnt》=ticks)break; //时间超过/等于要延迟的时间,则退出。 } }; delay_osschedunlock(); //恢复OS调度 } //延时nms //nms:要延时的ms数 void delay_ms(u16 nms) { if(delay_osrunning&&delay_osintnesting==0) //如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度) { if(nms》=fac_ms) //延时的时间大于OS的最少时间周期 { delay_ostimedly(nms/fac_ms); //OS延时 } nms%=fac_ms; //OS已经无法提供这么小的延时了,采用普通方式延时 } delay_us((u32)(nms*1000)); //普通方式延时 } #else //不用OS时 //延时nus //nus为要延时的us数。 void delay_us(u32 nus) { u32 temp; SysTick-》LOAD=nus*fac_us; //时间加载 SysTick-》VAL=0x00; //清空计数器 SysTick-》CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 do { temp=SysTick-》CTRL; }while((temp&0x01)&&!(temp&(1《《16))); //等待时间到达 SysTick-》CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器 SysTick-》VAL =0X00; //清空计数器 } //延时nms //注意nms的范围 //SysTick-》LOAD为24位寄存器,所以,最大延时为: //nms《=0xffffff*8*1000/SYSCLK //SYSCLK单位为Hz,nms单位为ms //对72M条件下,nms《=1864 void delay_ms(u16 nms) { u32 temp; SysTick-》LOAD=(u32)nms*fac_ms; //时间加载(SysTick-》LOAD为24bit) SysTick-》VAL =0x00; //清空计数器 SysTick-》CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 do { temp=SysTick-》CTRL; }while((temp&0x01)&&!(temp&(1《《16))); //等待时间到达 SysTick-》CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器 SysTick-》VAL =0X00; //清空计数器 } #endif 五、IIC.H #ifndef __IIC_H #define __IIC_H #include “sys.h” // //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //Mini STM32开发板 //IIC 驱动函数 //正点原子@ALIENTEK //技术论坛:www.openedv.com //修改日期:2010/6/10 //版本:V1.0 //版权所有,盗版必究。 //Copyright(C) 正点原子 2009-2019 //All rights reserved // /* //IO方向设置 #define SDA_IN() {GPIOC-》CRH&=0XFFFF0FFF;GPIOC-》CRH|=8《《12;} #define SDA_OUT() {GPIOC-》CRH&=0XFFFF0FFF;GPIOC-》CRH|=3《《12;} //IO操作函数 #define IIC_SCL PCout(12) //SCL #define IIC_SDA PCout(11) //SDA #define READ_SDA PCin(11) //输入SDA */ //IO方向设置 #define SDA_IN() {GPIOA-》CRL&=0X0FFFFFFF;GPIOA-》CRL|=8《《28;} #define SDA_OUT() {GPIOA-》CRL&=0X0FFFFFFF;GPIOA-》CRL|=3《《28;} //IO操作函数 #define IIC_SCL PAout(6) //SCL #define IIC_SDA PAout(7) //SDA #define READ_SDA PAin(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 六、IIC.C #include “iic.h” #include “delay.h” // //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //Mini STM32开发板 //IIC 驱动函数 //正点原子@ALIENTEK //技术论坛:www.openedv.com //修改日期:2010/6/10 //版本:V1.0 //版权所有,盗版必究。 //Copyright(C) 正点原子 2009-2019 //All rights reserved // /* //初始化IIC void IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; //RCC-》APB2ENR|=1《《4;//先使能外设IO PORTC时钟 RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE ); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); IIC_SCL=1; IIC_SDA=1; }*/ void IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE ); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //PA6 SCL GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //PA7 SDA GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); IIC_SCL=1; IIC_SDA=1; } //产生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; delay_us(4); IIC_SDA=1;//发送I2C总线结束信号 } //等待应答信号到来 //返回值: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; txd《《=1; delay_us(2); //对TEA5767这三个延时都是必须的 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; } 七、24CXX.H #ifndef __24CXX_H #define __24CXX_H #include “iic.h” //Mini STM32开发板 //24CXX驱动函数(适合24C01~24C16,24C32~256未经过测试!有待验证!) //正点原子@ALIENTEK //2010/6/10 //V1.2 #define AT24C01 127 #define AT24C02 255 #define AT24C04 511 #define AT24C08 1023 #define AT24C16 2047 #define AT24C32 4095 #define AT24C64 8191 #define AT24C128 16383 #define AT24C256 32767 #define AT24C512 65535 //Mini STM32开发板使用的是24c02,所以定义EE_TYPE为AT24C02 //#define EE_TYPE AT24C02 #define EE_TYPE AT24C512 u8 AT24CXX_ReadOneByte(u16 ReadAddr); //指定地址读取一个字节 void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite); //指定地址写入一个字节 void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);//指定地址开始写入指定长度的数据 u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len); //指定地址开始读取指定长度数据 void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite); //从指定地址开始写入指定长度的数据 void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead); //从指定地址开始读出指定长度的数据 u8 AT24CXX_Check(void); //检查器件 void AT24CXX_Init(void); //初始化IIC #endif 八、24CXX.C #include “24cxx.h” #include “delay.h” //Mini STM32开发板 //24CXX驱动函数(适合24C01~24C16,24C32~256未经过测试!有待验证!) //正点原子@ALIENTEK //2010/6/10 //V1.2 //初始化IIC接口 void AT24CXX_Init(void) { IIC_Init(); } //在AT24CXX指定地址读出一个数据 //ReadAddr:开始读数的地址 //返回值 :读到的数据 u8 AT24CXX_ReadOneByte(u16 ReadAddr) { u8 temp=0; IIC_Start(); if(EE_TYPE》AT24C16) { IIC_Send_Byte(0XA0); //发送写命令 IIC_Wait_Ack(); IIC_Send_Byte(ReadAddr》》8);//发送高地址 IIC_Wait_Ack(); //这句也得考虑注释掉 } else IIC_Send_Byte(0XA0+((ReadAddr/256)《《1)); //发送器件地址0XA0,写数据 //IIC_Wait_Ack(); //这句去掉就OK了,就可以通过AT24CXX_Check()了 IIC_Send_Byte(ReadAddr%256); //发送低地址 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(u16 WriteAddr,u8 DataToWrite) { IIC_Start(); if(EE_TYPE》AT24C16) { IIC_Send_Byte(0XA0); //发送写命令 IIC_Wait_Ack(); IIC_Send_Byte(WriteAddr》》8);//发送高地址 } else { IIC_Send_Byte(0XA0+((WriteAddr/256)《《1)); //发送器件地址0XA0,写数据 } IIC_Wait_Ack(); IIC_Send_Byte(WriteAddr%256); //发送低地址 IIC_Wait_Ack(); IIC_Send_Byte(DataToWrite); //发送字节 IIC_Wait_Ack(); IIC_Stop();//产生一个停止条件 delay_ms(10); } //在AT24CXX里面的指定地址开始写入长度为Len的数据 //该函数用于写入16bit或者32bit的数据。 //WriteAddr :开始写入的地址 //DataToWrite:数据数组首地址 //Len :要写入数据的长度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的数据 //该函数用于读出16bit或者32bit的数据。 //ReadAddr :开始读出的地址 //返回值 :数据 //Len :要读出数据的长度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的最后一个地址来存储标志字.24C02是255,24C512是65535 //如果用其他24C系列,这个地址要修改 //返回1:检测失败 //返回0:检测成功 u8 AT24CXX_Check(void) { u8 temp; temp=AT24CXX_ReadOneByte(65535);//避免每次开机都写AT24CXX if(temp==0X55) return 0; else//排除第一次初始化的情况 { AT24CXX_WriteOneByte(65535,0X55); temp=AT24CXX_ReadOneByte(65535); if(temp==0X55) return 0; } return 1; } //在AT24CXX里面的指定地址开始读出指定个数的数据 //ReadAddr :开始读出的地址 对24c02为0~255 //pBuffer :数据数组首地址 //NumToRead:要读出数据的个数 void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead) { while(NumToRead) { *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++); NumToRead--; } } //在AT24CXX里面的指定地址开始写入指定个数的数据 //WriteAddr :开始写入的地址 对24c02为0~255 //pBuffer :数据数组首地址 //NumToWrite:要写入数据的个数 void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite) { while(NumToWrite--) { AT24CXX_WriteOneByte(WriteAddr,*pBuffer); WriteAddr++; pBuffer++; } } /* AT24C512的读写问题?- 百度文库 https://wenku.baidu.com/view/cfc89adaa48da0116c175f0e7cd184254b351bb6.html 阿波罗F4/F7开发板例程不支持24C512的解决办法-OpenEdv-开源电子网 http://www.openedv.com/forum.php?mod=viewthread&tid=93162&highlight=24C512 */ 九、主程序main.c #include “led.h” #include “delay.h” #include “sys.h” #include “usart.h” //#include “lcd.h” #include “key.h” #include “24cxx.h” #include “iic.h” //ALIENTEK Mini STM32开发板范例代码19 //IIC实验 //技术支持:www.openedv.com //广州市星翼电子科技有限公司 //要写入到24Cxx的字符串数组 const u8 TEXT_Buffer[]={“MiniSTM32 IIC TEST”}; #define SIZE sizeof(TEXT_Buffer) int main(void) { //QQ:1447233384 u8 key; u16 i=0; u8 datatemp[SIZE]; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2 delay_init(); //延时函数初始化 uart_init(9600); //串口初始化为9600 LED_Init(); //初始化与LED连接的硬件接口 //LCD_Init(); KEY_Init(); //按键初始化 AT24CXX_Init(); //IIC初始化 printf(“开机成功rn”); while(AT24CXX_Check())//检测不到24c02 { //LCD_ShowString(60,150,200,16,16,“24C02 Check Failed!”); printf(“检测不到rn”); delay_ms(500); //LCD_ShowString(60,150,200,16,16,“Please Check! ”); delay_ms(500); printf(“请检查rn”); LED0=!LED0;//DS0闪烁 } printf(“检测存在rn”); printf(“read t %d t.rn”, AT24CXX_ReadOneByte(65535) ); //读出AT24CXX_Check()中65535位置中的数值 while(1) { key=KEY_Scan(0); if(key==WKUP_PRES)//WK_UP 按下,写入24C02 { //LCD_Fill(0,170,239,319,WHITE);//清除半屏 //LCD_ShowString(60,170,200,16,16,“Start Write 24C02.。..”); printf(“Start Write 24C512.。..rn”); AT24CXX_Write(0,(u8*)TEXT_Buffer,SIZE); //LCD_ShowString(60,170,200,16,16,“24C02 Write Finished!”);//提示传送完成 printf(“24C512 Write Finished!rn”); } if(key==KEY0_PRES)//KEY0 按下,读取字符串并显示 { //LCD_ShowString(60,170,200,16,16,“Start Read 24C02.。.. ”); printf(“Start Read 24C512.。.. rn”); AT24CXX_Read(0,datatemp,SIZE); //LCD_ShowString(60,170,200,16,16,“The Data Readed Is: ”);//提示传送完成 printf(“The Data Readed Is: %srn”,datatemp); //LCD_ShowString(60,190,200,16,16,datatemp);//显示读到的字符串 //printf(“Start Read 24C02.。.. rn”); } i++; delay_ms(10); if(i==20) { LED0=!LED0;//提示系统正在运行 i=0; } } } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1820 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1634 浏览 1 评论
1104 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
740 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1692 浏览 2 评论
1951浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
756浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
587浏览 3评论
605浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
569浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-31 00:41 , Processed in 0.896289 second(s), Total 47, Slave 41 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号