单片机模拟IIC,24C02程序有问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单片机模拟IIC,24C02程序有问题相关的知识,希望对你有一定的参考价值。

向IIC总线器件24c02EEPROM中发一组字符,并将它们读出送入P1,P1连接着灯,使灯逐次变化。。但我写的程序,P1口没有什么变化,真心不懂哪里有问题,求各路大神指点,谢谢~~
#include<reg51.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit sda=P2^1; //IO口定义
sbit scl=P2^0;
char code music[] = 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80;

uchar data buffer[100]; //用于缓存从24c02中读取的数据。

void delay(unsigned int m)

unsigned int n,p;
for(n=m;n>0;n--)
for(p=125;p>0;p--);

void nop()

_nop_();
_nop_();

/////////24C02读写驱动程序////////////////////
void delay1(unsigned int m)
unsigned int n;
for(n=0;n<m;n++);


void init() //24c02初始化子程序

scl=1;
nop();
sda=1;
nop();


void start() //启动I2C总线

sda=1;
nop();
scl=1;
nop();
sda=0;
nop();
scl=0;
nop();


void stop() //停止I2C总线

sda=0;
nop();
scl=1;
nop();
sda=1;
nop();


void writebyte(unsigned char j) //写一个字节

unsigned char i,temp;
temp=j;
for (i=0;i<8;i++)

temp=temp<<1;
scl=0;
nop();
sda=CY; //temp左移时,移出的值放入了CY中
nop();
scl=1;
nop();

scl=0;
nop();
sda=1;
nop();


unsigned char readbyte() //读一个字节

unsigned char i,j,k=0;
scl=0; nop(); sda=1;
for (i=0;i<8;i++)

nop(); scl=1; nop();
if(sda==1)
j=1;
else
j=0;
k=(k<<1)|j;
scl=0;

nop();
return(k);


void clock() //I2C总线时钟

unsigned char i=0;
scl=1;
nop();
while((sda==1)&&(i<255))
i++;
scl=0;
nop();


////////从24c02的地址address中读取一个字节数据/////
unsigned char read24c02(unsigned char address)

unsigned char i;
start();
writebyte(0xa0);
clock();
writebyte(address);
clock();
start();
writebyte(0xa1);
clock();
i=readbyte();
stop();
delay1(100);
return(i);


//////向24c02的address地址中写入一字节数据info/////
void write24c02(unsigned char address,unsigned char info)

start();
writebyte(0xa0);
clock();
writebyte(address);
clock();
writebyte(info);
clock();
stop();
delay1(5000);

void main()

uchar e,m,w;
init();
P1=0;
while(1)

for(e=0;e<8;e++)

write24c02(0x00+e,music[e]);
delay(5000);
// P1=radd(0x00+e);
// delay1(5000);

while(m!=e)

buffer[m]=read24c02(m);
delay(5000);
m++;

m=0;
while(w!=m)
P1=buffer[w];
w++;
delay(5000);

w=0;

参考技术A

没时间仔细看你程序,给你些经验参考!

    时序一定要符合i2c规范。SCL\\SDA 平常在H(高态),送出地址或资料时,先送出资料,然后

    再将SCL 从H -> L -> H (一个时钟);这样就送出1bit

    传送速率,不要超过2MHz ,也就是上面 H -> L -> H的时间要控制在2MHz内。

    传送时高位元先送,所以是左移,收的时候也是左移。

    接收资料跟1.相同,在SCL由高到低转态时读取。

    觉得新手比较容易弄错的是没完全弄懂时序(尤其是资料格式),另外就是速率。

    仔细看看24c02的datasheet,对照自己的程序,这样对自己帮助最大,应该能找出问题。

STM32实现0.96寸OLED显示模拟IIC和IIC四种实现(标准库和HAL库)

目录

本文通过四种方法实现OLED显示

设备选择

OLED介绍

接线表设计

OLED应用

1.标准库模拟IIC实现OLED显示

2.标准库IIC实现OLED显示

3.HAL库模拟IIC实现OLED显示

4.HAL库IIC实现OLED显示

实现效果

代码下载


本文通过四种方法实现OLED显示

设备选择

1.单片机:STM32F103

2.0.96寸OLED显示屏 

OLED介绍

OLED (Organic Light-Emitting Diode):有机发光二极管又称为有机电激光显示,OLED显示技术具有自发光的特性,采用薄的有机材料涂层和玻璃基板,当有电流通过时,这些有机材料就会发光,而且OLED显示屏幕可视角度大,功耗低。OLED由于同时具备自发光、不需背光源(只上电是不会亮的,驱动程序和接线正确才会点亮)、对比度高、厚度薄、视角广、反应速度快、可用于挠曲面板、使用温度范围广、结构及制程简单等优异之特性。最先接触的12864屏都是LCD的,需要背光,功耗较高,而OLED的功耗低,更加适合小系统;由于两者发光材料的不同,在不同的环境中,OLED的显示效果较佳。模块供电可以是3.3V也可以是5V,不需要修改模块电路,OLED屏具有多个控制指令,可以控制OLED的亮度、对比度、开关升压电路等指令。操作方便,功能丰富,可显示汉字、ASCII、图案等。
 

接线表设计

序号激光测距模块单片机STM32
1VCC3.3V/5V
2SCLPB6
3SDAPB7
4GNDGND

OLED应用

这里选用0.96寸OLED显示屏,它支持IIC通信,因此代码将以IIC展开。

整个实现过程,分为四种方式实现。

1.标准库模拟IIC实现OLED显示

/**************************************************/
/*               IIC Start                        */
/**************************************************/
void IIC_Start()


	OLED_GPIO(OLED_SDA,1);
	OLED_GPIO(OLED_CLK,1);
	OLED_GPIO(OLED_SDA,0);
	OLED_GPIO(OLED_CLK,0);


/**************************************************/
/*               IIC Stop                         */
/**************************************************/
void IIC_Stop()

	OLED_GPIO(OLED_CLK,1);
	OLED_GPIO(OLED_SDA,0);
	OLED_GPIO(OLED_CLK,1);
	
	OLED_GPIO(OLED_SDA,1);
	OLED_GPIO(OLED_CLK,1);
	


void IIC_Wait_Ack()  //检测应答

	OLED_GPIO(OLED_SDA,0);
	OLED_GPIO(OLED_CLK,1);
	OLED_GPIO(OLED_CLK,0);


/**************************************************/
/*             IIC Write byte                     */
/**************************************************/
void Write_IIC_Byte(uint8_t IIC_Byte)

	uint8_t i;
	uint8_t m,da;
	da=IIC_Byte;
	OLED_GPIO(OLED_CLK,0);

	for(i=0;i<8;i++)		
	
		m=da;
		//	OLED_SCLK_Clr();
		m=m&0x80;
		if(m==0x80)
		
			OLED_GPIO(OLED_SDA,1);
		
		else 
			OLED_GPIO(OLED_SDA,0);
		da=da<<1;
		OLED_GPIO(OLED_CLK,1);
		OLED_GPIO(OLED_CLK,0);

	



/*********************************************/
/*      	IIC Write Command		   	     */
/*********************************************/
void Write_IIC_Command(uint8_t IIC_Command) //写命令

	IIC_Start();
	Write_IIC_Byte(0x78);	// OLED的I2C地址(禁止修改)
	IIC_Wait_Ack();	
	Write_IIC_Byte(0x00);	// OLED 指令(禁止修改)			
	IIC_Wait_Ack();
	Write_IIC_Byte(IIC_Command); 
	IIC_Wait_Ack();	
	IIC_Stop();

/*********************************************/
/*       	IIC Write Data	  	   	         */
/*********************************************/
void Write_IIC_Data(uint8_t IIC_Data)   //写数据

	IIC_Start();
	Write_IIC_Byte(0x78);		// OLED的I2C地址(禁止修改)		
	IIC_Wait_Ack();	
	Write_IIC_Byte(0x40);		// OLED 数据(禁止修改)
	IIC_Wait_Ack();	
	Write_IIC_Byte(IIC_Data);
	IIC_Wait_Ack();	
	IIC_Stop();

void OLED_WR_Byte(uint8_t dat,uint8_t cmd) 

	if(cmd)
	
		Write_IIC_Data(dat);
	
	else 
	
		Write_IIC_Command(dat);
	

2.标准库IIC实现OLED显示

/**
  * @brief  I2C_Configuration,初始化硬件IIC引脚
  * @param  无
  * @retval 无
  */
void I2C_Configuration(void)

    I2C_InitTypeDef  I2C_InitStructure;
    GPIO_InitTypeDef  GPIO_InitStructure; 

    /*I2C1外设时钟使能 */
    OLED_I2C_CLK_INIT(OLED_I2C_CLK,ENABLE);

    /*I2C1外设GPIO时钟使能 */
    RCC_APB2PeriphClockCmd(OLED_I2C_SCL_GPIO_CLK | OLED_I2C_SDA_GPIO_CLK,ENABLE);

     /* I2C_SCL、I2C_SDA*/
  GPIO_InitStructure.GPIO_Pin = OLED_I2C_SCL_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;          // 开漏输出
  GPIO_Init(OLED_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = OLED_I2C_SDA_PIN;
  GPIO_Init(OLED_I2C_SDA_GPIO_PORT, &GPIO_InitStructure);   


    /* I2C 配置 */
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;    
  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;    /* 高电平数据稳定,低电平数据变化 SCL 时钟线的占空比 */
  I2C_InitStructure.I2C_OwnAddress1 =0x10;    //主机的I2C地址.和其它设备不重复即可
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;  
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; /* I2C的寻址模式 */
  I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;                             /* 通信速率 */

  I2C_Init(OLED_I2C, &I2C_InitStructure);                                         /* I2C1 初始化 */
  I2C_Cmd(OLED_I2C, ENABLE);                                                    /* 使能 I2C1 */



 /**
  * @brief  I2C_WriteByte,向OLED寄存器地址写一个byte的数据
  * @param  addr:寄存器地址
    *                   data:要写入的数据
  * @retval 无
  */
void I2C_WriteByte(uint8_t addr,uint8_t data)

	while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

	I2C_GenerateSTART(I2C1, ENABLE);//开启I2C1
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));/*EV5,主模式*/

	I2C_Send7bitAddress(I2C1, OLED_ADDRESS, I2C_Direction_Transmitter);//器件地址 -- 默认0x78
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

	I2C_SendData(I2C1, addr);//寄存器地址
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

	I2C_SendData(I2C1, data);//发送数据
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

	I2C_GenerateSTOP(I2C1, ENABLE);//关闭I2C1总线



 /**
  * @brief  WriteCmd,向OLED写入命令
  * @param  I2C_Command:命令代码
  * @retval 无
  */
void WriteCmd(unsigned char I2C_Command)//写命令

    I2C_WriteByte(0x00, I2C_Command);



 /**
  * @brief  WriteDat,向OLED写入数据
  * @param  I2C_Data:数据
  * @retval 无
  */
void WriteDat(unsigned char I2C_Data)//写数据

    I2C_WriteByte(0x40, I2C_Data);



 /**
  * @brief  OLED_Init,初始化OLED
  * @param  无
  * @retval 无
  */
void OLED_Init(void)

    delay_ms(1000);     // 1s,这里的延时很重要,上电后延时,没有错误的冗余设计

    WriteCmd(0xAE); //display off
    WriteCmd(0x20); //Set Memory Addressing Mode    
    WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
    WriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7
    WriteCmd(0xc8); //Set COM Output Scan Direction
    WriteCmd(0x00); //---set low column address
    WriteCmd(0x10); //---set high column address
    WriteCmd(0x40); //--set start line address
    WriteCmd(0x81); //--set contrast control register
    WriteCmd(0xff); //亮度调节 0x00~0xff
    WriteCmd(0xa1); //--set segment re-map 0 to 127
    WriteCmd(0xa6); //--set normal display
    WriteCmd(0xa8); //--set multiplex ratio(1 to 64)
    WriteCmd(0x3F); //
    WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
    WriteCmd(0xd3); //-set display offset
    WriteCmd(0x00); //-not offset
    WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency
    WriteCmd(0xf0); //--set divide ratio
    WriteCmd(0xd9); //--set pre-charge period
    WriteCmd(0x22); //
    WriteCmd(0xda); //--set com pins hardware configuration
    WriteCmd(0x12);
    WriteCmd(0xdb); //--set vcomh
    WriteCmd(0x20); //0x20,0.77xVcc
    WriteCmd(0x8d); //--set DC-DC enable
    WriteCmd(0x14); //
    WriteCmd(0xaf); //--turn on oled panel

3.HAL库模拟IIC实现OLED显示

static void OLED_GPIO_Init(void)

	GPIO_InitTypeDef GPIO_Struct;

	/* GPIO Ports Clock Enable */
	__HAL_RCC_GPIOB_CLK_ENABLE();

	GPIO_Struct.Pin = GPIO_PIN_7| GPIO_PIN_6;
	GPIO_Struct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_Struct.Speed =	GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOB, &GPIO_Struct);



void OLED_GPIO(uint8_t add,uint8_t date)

	if(add==0)
	
		if(date==1) HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);
		else if(date==0)HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);
	
	else if(add==1)
	
		if(date==1) HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);
		else if(date==0)HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
	

/**************************************************/
/*               IIC Start                        */
/**************************************************/
void IIC_Start()


	OLED_GPIO(OLED_SDA,1);
	OLED_GPIO(OLED_CLK,1);
	OLED_GPIO(OLED_SDA,0);
	OLED_GPIO(OLED_CLK,0);


/**************************************************/
/*               IIC Stop                         */
/**************************************************/
void IIC_Stop()

	OLED_GPIO(OLED_CLK,1);
	OLED_GPIO(OLED_SDA,0);
	OLED_GPIO(OLED_CLK,1);
	
	OLED_GPIO(OLED_SDA,1);
	OLED_GPIO(OLED_CLK,1);
	


void IIC_Wait_Ack()  //检测应答

	OLED_GPIO(OLED_SDA,0);
	OLED_GPIO(OLED_CLK,1);
	OLED_GPIO(OLED_CLK,0);


/**************************************************/
/*             IIC Write byte                     */
/**************************************************/
void Write_IIC_Byte(uint8_t IIC_Byte)

	uint8_t i;
	uint8_t m,da;
	da=IIC_Byte;
	OLED_GPIO(OLED_CLK,0);

	for(i=0;i<8;i++)		
	
		m=da;
		//	OLED_SCLK_Clr();
		m=m&0x80;
		if(m==0x80)
		
			OLED_GPIO(OLED_SDA,1);
		
		else 
			OLED_GPIO(OLED_SDA,0);
		da=da<<1;
		OLED_GPIO(OLED_CLK,1);
		OLED_GPIO(OLED_CLK,0);

	



/*********************************************/
/*      	IIC Write Command		   	     */
/*********************************************/
void Write_IIC_Command(uint8_t IIC_Command) //写命令

	IIC_Start();
	Write_IIC_Byte(0x78);	// OLED的I2C地址(禁止修改)
	IIC_Wait_Ack();	
	Write_IIC_Byte(0x00);	// OLED 指令(禁止修改)			
	IIC_Wait_Ack();
	Write_IIC_Byte(IIC_Command); 
	IIC_Wait_Ack();	
	IIC_Stop();

/*********************************************/
/*       	IIC Write Data	  	   	         */
/*********************************************/
void Write_IIC_Data(uint8_t IIC_Data)   //写数据

	IIC_Start();
	Write_IIC_Byte(0x78);		// OLED的I2C地址(禁止修改)		
	IIC_Wait_Ack();	
	Write_IIC_Byte(0x40);		// OLED 数据(禁止修改)
	IIC_Wait_Ack();	
	Write_IIC_Byte(IIC_Data);
	IIC_Wait_Ack();	
	IIC_Stop();

void OLED_WR_Byte(uint8_t dat,uint8_t cmd) 

	if(cmd)
	
		Write_IIC_Data(dat);
	
	else 
	
		Write_IIC_Command(dat);
	

4.HAL库IIC实现OLED显示

//写命令
void OLED_WR_CMD(uint8_t cmd)

	HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x00,I2C_MEMADD_SIZE_8BIT,&cmd,1,0x100);

//写数据
void OLED_WR_DATA(uint8_t data)

	HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x40,I2C_MEMADD_SIZE_8BIT,&data,1,0x100);




void WriteCmd()

  HAL_Delay(1000);     // 1s,这里的延时很重要,上电后延时,没有错误的冗余设计

	OLED_WR_CMD(0xAE); //display off
	OLED_WR_CMD(0x20); //Set Memory Addressing Mode    
	OLED_WR_CMD(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
	OLED_WR_CMD(0xb0); //Set Page Start Address for Page Addressing Mode,0-7
	OLED_WR_CMD(0xc8); //Set COM Output Scan Direction
	OLED_WR_CMD(0x00); //---set low column address
	OLED_WR_CMD(0x10); //---set high column address
	OLED_WR_CMD(0x40); //--set start line address
	OLED_WR_CMD(0x81); //--set contrast control register
	OLED_WR_CMD(0xff); //亮度调节 0x00~0xff
	OLED_WR_CMD(0xa1); //--set segment re-map 0 to 127
	OLED_WR_CMD(0xa6); //--set normal display
	OLED_WR_CMD(0xa8); //--set multiplex ratio(1 to 64)
	OLED_WR_CMD(0x3F); //
	OLED_WR_CMD(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
	OLED_WR_CMD(0xd3); //-set display offset
	OLED_WR_CMD(0x00); //-not offset
	OLED_WR_CMD(0xd5); //--set display clock divide ratio/oscillator frequency
	OLED_WR_CMD(0xf0); //--set divide ratio
	OLED_WR_CMD(0xd9); //--set pre-charge period
	OLED_WR_CMD(0x22); //
	OLED_WR_CMD(0xda); //--set com pins hardware configuration
	OLED_WR_CMD(0x12);
	OLED_WR_CMD(0xdb); //--set vcomh
	OLED_WR_CMD(0x20); //0x20,0.77xVcc
	OLED_WR_CMD(0x8d); //--set DC-DC enable
	OLED_WR_CMD(0x14); //
	OLED_WR_CMD(0xaf); //--turn on oled panel

实现效果

 由于频闪的原因,拍不全。

从代码上可以发现,IIC实现比模拟IIC实现起来要简单不少。

代码下载

创作不易,下面提供下载链接,涉及以上四种实现方法源码。

如有问题或需求可私信交流

源码下载地址:

STM32实现0.96寸OLED显示模拟IIC和IIC四种实现(标准库和HAL库)-C文档类资源-CSDN文库

吾芯电子工作室

以上是关于单片机模拟IIC,24C02程序有问题的主要内容,如果未能解决你的问题,请参考以下文章

51单片机 24C02器件读写+Proteus仿真

单片机: EEPROM和串口通信

在板子上的24C02怎么写程序进去

关于24c02芯片的程序问题,希望得到帮助解决,下面的程序有啥问题,为啥下载到单片机里面不能运行!

单片机24c02程序求助

模拟IIC协议时序