STM32编程之软件模拟IIC对24C02存储器读写操作

发布者:tau29最新更新时间:2016-09-23 来源: eefocus关键字:STM32  模拟IIC  24C02存储器  读写操作 手机看文章 扫描二维码
随时随地手机看文章
1、主程序

#include "stm32f10x_conf.h"
#include "led.h"
#include "key.h"
#include "usart.h"
#include "lcd.h"
#include "24cxx.h"
#include "myiic.h"
#include "delay.h"
u8 tabel[]="write data is:0 1 2 3 4 5 6 7 8 9 ";
/*
程序功能:STM32实现24C02读写操作
          当按下KEY1时,向24C02写入数组中的数据;
          当按下KEY2时,从24C02中读出数据到数组。
          用LCD液晶显示操作过程;
          用串口显示写入和读出的数据。
          LED0指示程序的工作状态。
作者:王庐山
日期:2015年7月24日
地点:湖北工业职业技术学院电子工程系
硬件连接:PC12--SCL
          PC11--SDA
备注:采用软件模拟IIC来实现的。

*/

int main(void)
{
    u8 i=0;
    delay_init();
    LED_Init();
    key_init();
    uart_init(9600);
    LCD_Init();
    AT24CXX_Init();
    LCD_Clear(RED);
    POINT_COLOR=BLUE;
    LCD_ShowString(30,60,200,16,16,"24c02_IIC test! ");
    LCD_ShowString(30,80,200,16,16,"press k1 to write.");
    LCD_ShowString(30,100,200,16,16,"press k2 to read.");
  while(AT24CXX_Check()==1)
    {
    LCD_ShowString(30,120,200,16,16,"error,please check!");    
    }
    
  while(1)
    {
    switch(keyscan())
        {
            case 1:
                {
                LCD_ShowString(30,120,200,16,16,"24c02 is writing!"); 
                AT24CXX_Write(0X0000,tabel,sizeof(tabel)-1);
                printf("24c02 is writing! \n");
                printf("Write data is:%s\n",tabel);
                    break;   
                }
             case 2:
                {
                LCD_ShowString(30,120,200,16,16,"24c02 is reading!"); 
                AT24CXX_Read(0X0000,tabel,sizeof(tabel)-1);
               printf("24c02 is reading! \n");
                    
                printf("Read data is:%s\n",tabel);
                    break;   
                }        
             default:break;
        }
        delay_ms(10);
        i++;
        if(i>25)
        {i=0;LED0=~LED0;}
    }

}

 

2、IIC驱动程序

#include "myiic.h"
#include "delay.h"
/*
程序功能:通用STM32系列IIC总线软件模拟方式驱动程序

*/
 

//初始化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_12|GPIO_Pin_11;
 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;

}
//产生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; 
 IIC_SDA=1;//发送I2C总线结束信号
 delay_us(4);           
}
//等待应答信号到来
//返回值: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;
}

void SDA_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//GPIO_Mode_IN_FLOATING
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure);

}

void SDA_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure);

}

 

IIC驱动头文件

#ifndef __MYIIC_H
#define __MYIIC_H
#include "sys.h"
/*
程序功能:通用STM32系列IIC总线软件模拟方式驱动程序头文件
*/
            
//IO方向设置
/* 方法1 :用寄存器的方式来实现
#define SDA_IN()  {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=8<<12;}
#define SDA_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3<<12;}*/
//方法2:用函数的方法来实现
void SDA_IN();
void SDA_OUT();

//IO操作函数  
#define IIC_SCL    PCout(12) //SCL
#define IIC_SDA    PCout(11) //SDA  
#define READ_SDA   PCin(11)  //输入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

 

3、24C02读写驱动

#include "24cxx.h" 
#include "delay.h"

//初始化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(); 
    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  {
  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  {
  temp<<=8;
  temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);          
 }
 return temp;                
}
//检查AT24CXX是否正常
//这里用了24XX的最后一个地址(255)来存储标志字.
//如果用其他24C系列,这个地址要修改
//返回1:检测失败
//返回0:检测成功
u8 AT24CXX_Check(void)
{
 u8 temp;
 temp=AT24CXX_ReadOneByte(255);//避免每次开机都写AT24CXX      
 if(temp==0X55)return 0;     
 else//排除第一次初始化的情况
 {
  AT24CXX_WriteOneByte(255,0X55);
     temp=AT24CXX_ReadOneByte(255);   
  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++;
 }
}


24C驱动头文件

 

#ifndef __24CXX_H
#define __24CXX_H
#include "myiic.h"  

#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  
//Mini STM32开发板使用的是24c02,所以定义EE_TYPE为AT24C02
#define EE_TYPE AT24C02
       
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

关键字:STM32  模拟IIC  24C02存储器  读写操作 引用地址:STM32编程之软件模拟IIC对24C02存储器读写操作

上一篇:基于stm32的can总线彻底研究
下一篇:STM32编程之用TIM定时器的输入捕获功能红外遥控解码

推荐阅读最新更新时间:2024-03-16 15:11

STM32 定时器详解
前言 STM32 单片机的定时器分为高级定时器、 通用定时器 、基本定时器三种。这三个定时器成上下级的关系,即基本定时器有的功能通用定时器都有,而且还增加了向下、向上/向下计数器、PWM生成、输出比较、输入捕获等功能; 而高级定时器又包含了通用定时器的所有功能,另外还增加了死区互补输出、刹车信号。(此处我们暂时忽略,暂时我们暂时还不需要接触这些功能) 一、STM32 通用定时器简介 通用定时器是一个通过可编程预分频器驱动的16位自动装载计数器构成。它适用于多种场合,包括测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)。使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个
[单片机]
STM32串口通信实验-库函数
这里先给出程序源码: 调用库函数: #include sys.h #include usart.h #include led.h #include delay.h int main() { u8 i; u8 len; u32 times = 0; //中断分组 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //初始化延时函数 delay_init(84); //初始化串口 uart_init(115200); //初始化led LED_Init(); //循环 LED0 = 0; while (1) { //检验接受标志 //若接
[单片机]
<font color='red'>STM32</font>串口通信实验-库函数
这8种STM32中GPIO工作模式,你都知道吗?
一、推挽输出:可以输出高、低电平,连接数字器件;推挽结构一般是指两个三极管分别受两个互补信号的控制,总是在一个三极管导通的时候另一个截止。高低电平由IC的电源决定。 推挽电路是两个参数相同的三极管或MOSFET,以推挽方式存在于电路中,各负责正负半周的波形放大任务,电路工作时,两只对称的功率开关管每次只有一个导通,所以导通损耗小、效率高。输出既可以向负载灌电流,也可以从负载抽取电流。推拉式输出级既提高电路的负载能力,又提高开关速度。 二、开漏输出:输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行。适合于做电流型的驱动,其吸收电流的能力相对强(一般20mA以内)。开漏形式的电路有以下几个特点: 1、利用外部电
[单片机]
这8种<font color='red'>STM32</font>中GPIO工作模式,你都知道吗?
STM32 LL库为什么比HAL库高效呢?
概 述 有些应用要求MCU能高效处理,特别是跑一些算法时,对CPU执行效率要求较高。 网上有很多文章说STM32Cube HAL执行效率不高,代码量大等问题 ,导致很多还没有入门,或初学的读者就产生各种各样的疑惑。 说实话,HAL相对标准外设库来说确实存在代码效率不高、代码量大灯这些问题,那么与之对应的STM32Cube LL恰好避免了这样的问题。 LL能高效的原因 简单总结一下原因: 巧妙运用C语言静态、内联函数直接操作寄存器 。 当然,这是其中重要的原因,还有一些其它原因,这里暂不描述。 你会在LL库.h文件中发现大量类似,静态、内联函数直接读写寄存器的函数。 比如读写IO口: __STATIC_
[单片机]
<font color='red'>STM32</font> LL库为什么比HAL库高效呢?
STM32学习之串口
第一步:把串口用的引脚设置。接收的为 GPIO_Mode_IN_FLOATING; //浮空输入 发送的为GPIO_Mode_AF_PP; // 复用推挽输出 第二部设置 void NVIC_Configuration(void) NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel ; // 全局中断、、 NVIC_InitStructure.NVIC_IRQChannelPreemptio
[单片机]
关于STM32像EPROM一样可以单字节写内部Flash的理解
都有说STM32的内部Flash可以像EPROM一样操作,单个字节单个字节的写入。根据本人的拙见,其实也就仅仅是“像”而已。原因有以下几点: 1.首先Flash这种东西,其写入数据的原理是便是将1变成0,所以你的某地址Flash一旦已经写过数据而且不为0,则当你再次需要向该地址写数据时,必须要先擦除,即把该地址先全部变成1,否则你将数据写入该地址后,基本上该地址里面的值已经不是你写入的值了。 2.STM32对内部Flash有页(1k或者2K)擦除指令,也就是STM32不能单独对某一个或者某几个字节进行擦除。而擦除操作并不需要大量内存。 3.如果要像EPROM一样操作Flash,其原理是先把该一页里面的数据全部读到一个b
[单片机]
STM32入门学习笔记之温湿度采集实验4
11.5 DS18B20例程 功能实现:读取DS18B20的温度显示在TFTLCD上。 (1)创建ds18b20.h文件,并输入以下代码。 #ifndef _DS18B20_H_ #define _DS18B20_H_ #include sys.h /********************************************************************************************************* 端 口 分 配 ********************************************
[单片机]
STM32学习日志——定时器中断实验
今天学习的是通用定时器及其中断,首先是内部时钟的选择,定时器的时钟Tclk是由APB1时钟乘以1或2决定的,至于是1还是2,要看APB1的分频系数(AHB/APB1),如果为1,则乘以1,否则乘以2。接着就可以根据我们想设定的时间Tout,去配置ARR跟PSC,这两个数是存在16位的寄存器,所以他们的范围为(0-65535),在这个范围内任意取值,满足公式即可。如果我么要配置500ms,可将ARR配置为2499,PSC配置为14399。也就是定时器计数的一个周期为500ms。(ARR为自动重装载值,PSC为Tclk的预分频系数) 根据步骤去写程序就很简单了。 实现功能:通过定时器的中断控制一个绿灯翻转,时间为500ms
[单片机]
<font color='red'>STM32</font>学习日志——定时器中断实验
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
更多每日新闻
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved