下面内容来自小蜜蜂老师公众号更新内容,讲了AT24C02 、PCF8591、以及led和数码管冲突问题,在更新的内容中小蜜蜂老师换了之前对锁存器初始化的写法,主要是加了一句所有锁存器都不选择的代码,更好的可以避免不同操作之间的影响,其次在进行锁存器操作端口赋值的时候也换了写法,之前是先选择要操作的锁存器后再进行赋值,现在是先将要赋的值送到端口然后在打开锁存器。
小蜜蜂老师操作总结 yyds
在编程中应该把握的原则是,P0端口的数据只送到目标外设。我的一个经验是:在上电初始化完成时,把所有外设连接的锁存器关闭;在需要对目标外设传输数据时,先把数据送到P0端口,然后再打开外设对应的锁存器,用完马关闭锁存器。保证在不需要的时候P0端口的变化不影响任何外设,在需要控制时,外设只接收正确的信息
一、灯闪烁与数码管计数
#include "reg52.h"
sbit LED1 = P0^0;
sbit LED2 = P0^1;
sbit LED8 = P0^7;
unsigned char led_stat = 0xff;
unsigned char value1 = 0,value2 = 0;
unsigned char code smg_data[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8, 0x80,0x90};
void SMG_Display_Data(void);//1.简单延时
void delay(unsigned int t)
{
while(t--);
}
void Delay_s(unsigned int t)
{
while(t--)
{
SMG_Display_Data(); //在延时期间保持数码管刷新
}
}
//2.锁存器初始化
void Init_74HC138(unsigned char channel)
{
switch(channel)
{
case 4:P2 = (P2 & 0x1f) | 0x80;break;//Y4输出0,LED控制
case 5:P2 = (P2 & 0x1f) | 0xa0;break;//Y5输出0,蜂鸣器和继电器控制
case 6:P2 = (P2 & 0x1f) | 0xc0;break; //Y6输出0,数码管位选
case 7:P2 = (P2 & 0x1f) | 0xe0;break;//Y7输出0,数码管段码
case 0:P2 = (P2 & 0x1f) | 0x00;break;//所有锁存器不选择
}
P2 = (P2 & 0x1f) | 0x00;//所有锁存器不选择
}
//3.数码管安位操作
void SMG_DisplayBit(unsigned char pos,unsigned char dat)
{
P0 = (0x01 << pos); //数码管的段位
Init_74HC138(6);
P0 = dat; //数码管显示内容
Init_74HC138(7);
}
//4.操作所有数码管
void SMG_All(unsigned char dat)
{
P0 = 0xff; //数码管的段位
Init_74HC138(6);
P0 = dat; //数码管显示内容
Init_74HC138(7);
}
//5.系统初始化
void Init_System(void)
{
P0 = 0xff; //关闭所有led
Init_74HC138(4);
P0 = 0x00; //关闭蜂鸣器和继电器
Init_74HC138(5);
SMG_All(0xff); //关闭所有数码管
}
//6.数码管数据显示
void SMG_Display_Data(void)
{
SMG_DisplayBit(0,smg_data[value1]);
delay(200);
SMG_DisplayBit(1,0xff);
delay(200);
SMG_DisplayBit(2,0xff);
delay(200);
SMG_DisplayBit(3,0xff);
delay(200);
SMG_DisplayBit(4,0xff);
delay(200);
SMG_DisplayBit(5,0xff);
delay(200);
SMG_DisplayBit(6,smg_data[value2/10]);
delay(200);
SMG_DisplayBit(7,smg_data[value2%10]);
delay(200);
SMG_All(0xff);
delay(200);
}
//7.led操作
void Led_Tackle(void)
{
led_stat &= ~0x80; //led8电亮
P0 = led_stat;
Init_74HC138(4);
Delay_s(200);
led_stat |= 0x80; //熄灭
P0 = led_stat;
Init_74HC138(4);
Delay_s(200);
value2++;
if(value2 == 100)
{
value2 = 0;
}
//led1 和led2 灯同时翻转
if((led_stat & 0x03) == 0x03)
{
led_stat &= ~0x03;
}
else
{
led_stat |= 0x03;
}
P0 = led_stat;
Init_74HC138(4);
value1++;
if(value1 > 9)
{
value1 = 0;
}
}
void main(void)
{
Init_System();
while(1)
{
Led_Tackle();
SMG_Display_Data();
}
}
注意
在这个代码中需要我们注意的是,在进行led操作函数中我们进行延时的时候也要进行数码管的刷新显示,第一次写就只是简单延时没有进行数码管的刷新显示,结果就是数码管一直在跳led没有闪烁变化,在延时函数中加上数码管动态显示后就可以了。
二、24C02基本读写操作
#include "reg52.h"
#include "iic.h"
unsigned char dat1,dat2,dat3;
unsigned char code smg_data[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8, 0x80,0x90};
//1.简单延时
void delay(unsigned int t)
{
while(t--);
}
//2.锁存器操作
void Init_74HC138(unsigned char n)
{
switch(n)
{
case 4:P2 = (P2 & 0x1f) | 0x80;break;
case 5:P2 = (P2 & 0x1f) | 0xa0;break;
case 6:P2 = (P2 & 0x1f) | 0xc0;break;
case 7:P2 = (P2 & 0x1f) | 0xe0;break;
case 0:P2 = (P2 & 0x1f) | 0x00;break;
}
P2 = (P2 & 0x1f) | 0x00;
}
//3.数码管安位操作
void SMG_DisplayBit(unsigned char pos,unsigned char dat)
{
P0 = (0x01 << pos);
Init_74HC138(6);
P0 = dat;
Init_74HC138(7);
}
//关闭所有数码管
void SMG_Close(void)
{
P0 = 0xff;
Init_74HC138(6);
P0 = 0xff;
Init_74HC138(7);
}
//4.系统初始化
void Init_System(void)
{
Init_74HC138(0);
P0 = 0x00;
Init_74HC138(5);
P0 = 0xff;
Init_74HC138(4);
}
//5.数码管数据显示
void SMG_Display_Data(void)
{
SMG_DisplayBit(0,smg_data[dat1/10]);
delay(200);
SMG_DisplayBit(1,smg_data[dat1%10]);
delay(200);
SMG_DisplayBit(2,0xbf);
delay(200);
SMG_DisplayBit(3,smg_data[dat2/10]);
delay(200);
SMG_DisplayBit(4,smg_data[dat2%10]);
delay(200);
SMG_DisplayBit(5,0xbf);
delay(200);
SMG_DisplayBit(6,smg_data[dat3/10]);
delay(200);
SMG_DisplayBit(7,smg_data[dat3%10]);
delay(200);
SMG_Close();
delay(200);
}
//6.at24c02数据写
void AT24C02_Write(unsigned char addr,unsigned char dat)
{
IIC_Start(); //起始信号
IIC_SendByte(0xa0); //EEPROM的写设备地址
IIC_WaitAck(); //等待从机应答
IIC_SendByte(addr); //内存单元地址
IIC_WaitAck(); //等待从机应答
IIC_SendByte(dat); //内存写入数据
IIC_WaitAck(); //等待从机应答
IIC_Stop(); //停止信号
}
//7.at24c02数据读
unsigned char AT24C02_Read(unsigned char addr)
{
unsigned char tmp = 0;
//首先,进行一个伪写操作
IIC_Start(); //起始信号
IIC_SendByte(0xa0); //EEPROM的写设备地址
IIC_WaitAck(); //等待从机应答
IIC_SendByte(addr); //内存单元地址
IIC_WaitAck(); //等待从机应答
//然后,开始字节读操作
IIC_Start(); //起始信号
IIC_SendByte(0xa1); //EEPROM的读设备地址
IIC_WaitAck(); //等待从机应答
tmp = IIC_RecByte(); //读取内存中的数据
IIC_SendAck(1); //产生非应答信号
IIC_Stop(); //停止信号
return tmp;
}
//8.数据处理
void Read_Write_Data(void)
{
//先读取数据
dat1 = AT24C02_Read(0x01);
dat2 = AT24C02_Read(0x03);
dat3 = AT24C02_Read(0x05);
dat1 = dat1 +1;
dat2 = dat2 +2;
dat3 = dat3 + 3 ;
if( dat1 > 10)
{
dat1 = 0;
}
if(dat2 > 20)
{
dat2 = 0;
}
if(dat3 > 30)
{
dat3 = 0;
}
//将数据写回去
AT24C02_Write(0x01,dat1);
delay(1000);
AT24C02_Write(0x03,dat2);
delay(1000);
AT24C02_Write(0x05,dat3);
delay(1000);
}
void main(void)
{
Init_System();
Read_Write_Data();
while(1)
{
SMG_Display_Data();
}
}
三、24C02存储按键触发次数
#include "iic.h"
#include "reg52.h"
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;
unsigned char s4_value = 0,s5_value = 0,s6_value = 0;
unsigned char code smg_data[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8, 0x80,0x90};
//1.简单延时
void delay(unsigned int t)
{
while(t--);
}
//2.锁存器初始化
void Init_74HC138(unsigned char channel)
{
switch(channel)
{
case 4:P2 = (P2 & 0x1f) | 0x80;break;
case 5:P2 = (P2 & 0x1f) | 0xa0;break;
case 6:P2 = (P2 & 0x1f) | 0xc0;break;
case 7:P2 = (P2 & 0x1f) | 0xe0;break;
case 0:P2 = (P2 & 0x1f) | 0x00;break;
}
P2 = (P2 & 0x1f) | 0x00;
}
//3.数码管安位操作
void SMG_DisplayBit(unsigned char pos,unsigned char dat)
{
P0 = (0x01 << pos);
Init_74HC138(6);
P0 = dat;
Init_74HC138(7);
}
//4.操作所有数码管
void SMG_All(unsigned char dat)
{
P0 = 0xff;
Init_74HC138(6);
P0 = dat;
Init_74HC138(7);
}
//5.系统初始化
void Init_System(void)
{
P0 = 0xff;
Init_74HC138(4);
P0 = 0x00;
Init_74HC138(5);
SMG_All(0xff);
}
//6.数码管显示数据
void SMG_Display_Data(void)
{
SMG_DisplayBit(0,smg_data[s4_value/10]);
delay(200);
SMG_DisplayBit(1,smg_data[s4_value%10]);
delay(200);
SMG_DisplayBit(2,0xbf);
delay(200);
SMG_DisplayBit(3,smg_data[s5_value/10]);
delay(200);
SMG_DisplayBit(4,smg_data[s5_value%10]);
delay(200);
SMG_DisplayBit(5,0xbf);
delay(200);
SMG_DisplayBit(6,smg_data[s6_value/10]);
delay(200);
SMG_DisplayBit(7,smg_data[s6_value%10]);
delay(200);
SMG_All(0xff);
delay(200);
}
//7.at24c02写数据
void AT24C02_Write(unsigned char addr,unsigned char dat)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
//8.at24c04读数据
unsigned char AT24C02_Read(unsigned char addr)
{
unsigned char temp = 0;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
temp = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
return temp;
}
//9.系统上电后,先从24C04存储器的0x00、0x01和0x02这三个地址单元读取数据
void AT24C02_Data_Init(void)
{
s4_value = AT24C02_Read(0x00);
delay(1000);
s5_value = AT24C02_Read(0x01);
delay(1000);
s6_value = AT24C02_Read(0x02);
delay(1000);
}
//10.按键控制
void Key_Scans(void)
{
if(S4 == 0)
{
delay(20);
if(S4 == 0)
{
while(S4 == 0);
s4_value++;
if(s4_value > 13)
{
s4_value = 0;
}
AT24C02_Write(0x00,s4_value);
}
}
if(S5 == 0)
{
delay(20);
if(S5 == 0)
{
while(S5 == 0);
s5_value++;
if(s5_value > 13)
{
s5_value = 0;
}
AT24C02_Write(0x01,s5_value);
}
}
if(S6 == 0)
{
delay(20);
if(S6 == 0)
{
while(S6 == 0);
s6_value++;
if(s6_value > 13)
{
s6_value = 0;
}
AT24C02_Write(0x02,s6_value);
}
}
}
void main(void)
{
Init_System();
AT24C02_Data_Init();
while(1)
{
SMG_Display_Data() ;
Key_Scans();
}
}
四、采样可变电阻电压与光敏电阻电压
#include "iic.h"
#include "reg52.h"
sbit S4 = P3^3;
unsigned char channel = 1;
unsigned int adc_value = 0,adc_volt = 0;
unsigned char code smg_data[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8, 0x80,0x90};
unsigned char code smg_dot[] ={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
//1.简单延时
void delay(unsigned int t)
{
while(t--);
}
//2.锁存器初始化
void Init_74HC138(unsigned char channel)
{
switch(channel)
{
case 4:P2 = (P2 & 0x1f) | 0x80;break;
case 5:P2 = (P2 & 0x1f) | 0xa0;break;
case 6:P2 = (P2 & 0x1f) | 0xc0;break;
case 7:P2 = (P2 & 0x1f) | 0xe0;break;
case 0:P2 = (P2 & 0x1f) | 0x00;break;
}
P2 = (P2 & 0x1f) | 0x00;
}
//数码管安位操作
void SMG_DisplayBit(unsigned char pos,unsigned char dat)
{
P0 = (0x01 << pos);
Init_74HC138(6);
P0 = dat;
Init_74HC138(7);
}
//操作所有数码管
void SMG_All(unsigned char dat)
{
P0 = 0xff;
Init_74HC138(6);
P0 = dat;
Init_74HC138(7);
}
//系统初始化
void Init_System(void)
{
P0 = 0xff;
Init_74HC138(4);
P0 = 0x00;
Init_74HC138(5);
SMG_All(0xff);
}
//数码管数据显示
void SMG_Display_Data(void)
{
SMG_DisplayBit(0,0xbf);
delay(200);
SMG_DisplayBit(1,smg_data[channel]);
delay(200);
SMG_DisplayBit(2,0xbf);
delay(200);
SMG_DisplayBit(3,0xff);
delay(200);
SMG_DisplayBit(4,0xff);
delay(200);
SMG_DisplayBit(5,smg_dot[adc_volt/100]);
delay(200);
SMG_DisplayBit(6,smg_data[adc_volt/10%10]);
delay(200);
SMG_DisplayBit(7,smg_data[adc_volt%10]);
delay(200);
SMG_All(0xff);
delay(200);
}
//PCF8591数据读取
void PCF8591_Read_Data(unsigned char channel)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
if(channel == 1)
{
IIC_SendByte(0x01);
}
else if(channel == 3)
{
IIC_SendByte(0x03);
}
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
adc_value = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
adc_volt = adc_value * (5.0/255)*100; //扩大100倍方便显示
}
//按键操作
void Key_Tackle(void)
{
if(S4 == 0)
{
delay(20);
if(S4 == 0)
{
while(S4 == 0)
{
if(channel == 1)
{
channel = 3;
}
else if(channel == 3)
{
channel = 1;
}
PCF8591_Read_Data(channel);
SMG_Display_Data();
}
}
}
}
//主函数
void main(void)
{
Init_System();
while(1)
{
Key_Tackle();
PCF8591_Read_Data(channel);
SMG_Display_Data();
}
}
加油