标题:
C51单片机设定位闪烁关闭不掉 附程序
[打印本页]
作者:
宏达工控
时间:
2023-8-9 17:07
标题:
C51单片机设定位闪烁关闭不掉 附程序
#include<reg51.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
#define AT24C02_ADDRESS 0xA0 //0xA0 1010 00000写地址
uint Count;
uint Set_Count;
uint Num_L;
uint Num_H;
uint num1;
char num2=0;
sbit I2C_SCL= P1^6;
sbit I2C_SDA= P1^7;
sbit Start_Dianji=P3^0; //电机启动_dianji
sbit forward=P3^1; //正转检测
//sbit back=P3^1; //反转检测
sbit run=P3^7; //运行信号
sbit jia_up=P1^0;// 增加键
sbit jian_down=P1^1;//减少键
sbit yiwei_up=P1^2; //移位键
sbit qingling=P1^3; //清零键
uchar code ledcode[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //共阴数码管编码0-9 modtable={ {0,0,0,0},{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1} ,{1,1,1,1} }
uchar data Ledbuff[]={0, 0, 0, 0, 0, 0, 0, 0};//显示缓冲区
unsigned char n = 0, n_50ms; //添加闪烁.n=数码管移动位数
bit flag; //添加闪烁
#define I2CDelay_us(){_nop_();_nop_();_nop_();_nop_();}//voidI2CDelay_us
/***********************
AT24C初始化I2C_init
*************************/
void I2C_init()
{
I2C_SCL=1;
I2C_SDA=1;//首先确保SCL SDA都是高电平
}
/***********************
产生总线起始信号I2C_Start
*************************/
void I2C_Start(void )
{
I2C_SDA=1;//首先确保SCL SDA都是高电平
I2C_SCL=1; //确保SCL高电平
I2C_SDA=0;//先在SCL为高时拉低SDA,即为起始信号
I2C_SCL=0; //在拉低 SCL,钳住I2C总线准备发送或接收数据
}
/***********************
产生总线停止信号:先拉低SDA在拉低SCL
*************************/
void I2C_Stop(void )
{
I2C_SDA=0;//首先确保SCL SDA都是低电平
I2C_SCL=1; //先拉高 SCL
I2C_SDA=1;//在拉高 SDA
}
/*******************************************************************************
*@brief I2C发送一个字节数据
*@param Byte要发送的字节
*@retval 无
起始信号后必须送一个从机地址(7)位,1-7位为要接收器件的地址,第八位读写位0发送1接收,第9位ACK应答位,
紧接着为第一个数据字节,然后一位应答位ACK后面继续第二个数据字节
**********************************************************************************/
void I2C_SendByte(unsigned char Byte)
{
unsigned char i;
for(i=0;i<8;i++)
{
I2C_SDA=Byte&(0x80>>i); //1000 0000右移 i个位
I2C_SCL=1; //先拉高 SCL
I2C_SCL=0; //SCL
}
}
/***********************************************************************************************
*@brief I2C读取 接收一个字节
*@param 无
*@retval 读取 接收到的一个字节数据
********************************************************************************************/
unsigned char I2C_ReceiveByte(void)
{
unsigned char i,Byte=0x00;//
I2C_SDA=1; //
for(i=0;i<8;i++)
{
I2C_SCL=1; //先拉高 SCL
if(I2C_SDA){Byte |= (0x80>>i); }
I2C_SCL=0; //SCL
}
return Byte;
}
/*********************
*@brief I2C发送应答Ack
*@param AckBit应答位 0为应答(成功) 1为非应答(失败)
*@retval 无
************************/
void I2C_SendAck(unsigned char AckBit)
{
I2C_SDA=AckBit;
I2C_SCL=1; //先拉高 SCL
I2C_SCL=0; //SCL
}
/*********************
*@brief I2C接收应答位
*@param 无
*@retval AckBit应答位 0为应答(成功) 1为非应答(失败)
************************/
unsigned char I2C_ReceiveAck(void)
{
unsigned char AckBit;
I2C_SDA=1;
I2C_SCL=1; //先拉高 SCL
AckBit=I2C_SDA;
I2C_SCL=0; //SCL
I2C_SDA=1;//少此行错误不能读取
return AckBit; //返回值
}
/**********向AT24C写数据***********
*@brief AT24C写入一个字节
*@param WordAddress要写入字节的地址
*@param Data要写入的数据
*@retval无
写多字节时,写入一个字节。在写一个字节前,必须延时5ms
************************/
void AT24C_WriteByte(unsigned char WordAddress,Data)
{
I2C_Start();//启动总线
I2C_SendByte(AT24C02_ADDRESS);//发送写操作地址+写数据(0xa0)
I2C_ReceiveAck(); //等待应答
I2C_SendByte(WordAddress);//要写入的地址
I2C_ReceiveAck(); //等待应答完成
I2C_SendByte(Data); //要写入的数据,第一字节 ,第二字节注意:每个字节都回应一个应答位0,如果没有回应说明写入不成功
I2C_ReceiveAck(); //等待完成 注意:每个字节都回应一个应答位0,如果没有回应说明写入不成功
I2C_Stop(); //发送结束信号:停止总线
}
/************从AT24C中读出数据*********
*@brief AT24C读取一个字节
*@param WordAddress要读出字节的地址
*@param 无
*@retval要读出的数据
************************/
unsigned char AT24C_ReadByte(unsigned char WordAddress) //void
{
unsigned char Data;
I2C_Start(); //发送起始信号:启动总线
I2C_SendByte(AT24C02_ADDRESS); //接上首字节,发送器件写操作地址+写数据(0xa0)这里写操作时维纶把所要读的数据地址AT24C02_ADDRESS通知读取哪个地址信息
I2C_ReceiveAck(); //等待完成应答
I2C_SendByte(WordAddress);//发送要读取内存的地址(WORD ADDRESS)
I2C_ReceiveAck(); //等待应答完成
I2C_Start();//在次启动总线
I2C_SendByte(AT24C02_ADDRESS| 0x01); //对E2PROM进行读操作(0XA1)E2PROM会自动向主机发回数据,读取一个字节后回应一个应答位,后会继续传送下一个地址的数据0xa1
I2C_ReceiveAck(); //等待完成
Data= I2C_ReceiveByte(); //要读出的数据到Data
I2C_SendAck(1); //等待完成::如果不想读了,就发送一个非应答位NAK(1),发送结束,停止总线
I2C_Stop(); //停止总线
return Data ;//返回值
}
/************延时函数***********************/
void delay_ms(uint ms)
{
uchar k;
while(ms--)
{
for(k = 0; k < 120; k++);
}
}
///////////////////////////////////////////////////////////////
void display() //显示程序display(uchar a,b,c,d,e)
{
unsigned char i,w = 1;//添加闪烁 i, w = 128
/********************************/
switch(i)//使用多分支选择语句 i=count display 0x代表16进制
{
case(0):Ledbuff[7]=Set_Count/1000;break; //取设定千位字符送缓存
case(1):Ledbuff[6]=Set_Count/100%10;break; //取设定百位字符送缓冲
case(2):Ledbuff[5]=Set_Count/10%10;break; //取设定十位字符送缓冲
case(3):Ledbuff[4]=Set_Count%10;break; //取设定个位字符送缓存
case(4):Ledbuff[3]=Count/1000;break; //取计数千位字符送缓存
case(5):Ledbuff[2]=Count/100%10;break;
case(6):Ledbuff[1]=Count/10%10;break;
case(7):Ledbuff[0]=Count%10;break;
}
P0=0x00; //消阴:段码全部低电平关闭
//添加闪烁: 闪烁字符 0,N闪烁位置 Ledbuff[n] = 10; Ledbuff[ n ] = i Ledbuff[ n+3 ] 是从第四个字符开始闪烁
if (flag) Ledbuff[ n+3 ] = 245 ; //共阴字码表取反10 ,共阳=10 因为n是从1开始,所以第一个闪烁的是Ledbuff[4] ~10=(0000 1010)
/**********************************/
P2=~(0x01<<i); //P2位选,左移i位取反
P0=ledcode[Ledbuff[i]]; //P0字符刷新显示
delay_ms(1); //显示2MS
i=++i%8; //自加1
}
void Adjust() //按键设定匝数,用P2.4个位-P2.7(千位)前四位数码管显示void
{
// **********原程序************************
if(yiwei_up==0) //移位按键按下
{
//********这里开启定时中断,进入闪烁计时**************************
while(!yiwei_up); //等待移位按键松开
{
n ++; if(n>4) n=1; //移位:左移一位 ,移到千位后,在按返回个位
}
ET0=1; //开启T0
TR0 = 1; // 启动T0 工作开始 选择的数码管开始闪烁
}
//加减按键检测
if(Set_Count>=0 && Set_Count<9999)//最大9999yiwei_Count=0; //设定加 jia_up==0
{
if (jia_up==0) //增加按键按下
{
while(!jia_up);//等待加按键松开
num1=Set_Count ;
{
if (n == 1 ) //
{
Set_Count += 1; //设定+1
}
if ( n == 2 &&Set_Count<9990)
{
Set_Count += 10; //设定+10
}
if ( n == 3 && Set_Count<9900 )
{
Set_Count += 100; //设定+100
}
if ( n == 4 && Set_Count<9000 )
{
Set_Count += 1000; //设定+1000
}
}
}
if (jian_down==0) //减少按键按下
{
while(!jian_down);//等待按键松开
num1=Set_Count ;
{
if ( n ==1 && Set_Count>1 ) // 移位在个位
{
Set_Count -= 1; //设定-1
}
if ( n == 2 && Set_Count>9)
{
Set_Count -= 10; //设定+1
}
if (n == 3 && Set_Count>99 )
{
Set_Count -= 100; //设定-100
}
if ( n == 4 && Set_Count>999 )
{
Set_Count -= 1000; //设定+1
}
}
}
if ( num1 != Set_Count ) // 设定值有变化,存入24c
{
//写入数据
AT24C_WriteByte(0,Set_Count%256);
delay_ms(5) ; //显示2MS
AT24C_WriteByte(1,Set_Count/256);
delay_ms(5); //显示2MS
}
}
if( num2==3) //设定超时保存后,闪烁几次关闭闪烁
{ET0=1;TR0 = 0; num2=0 ;} //num2++ ;
num1=Set_Count ; //保存完成 将设定值送到设定值变化缓存
}
/**********************************************************
主函数 ET=1 // 是打开定时器0中断允许,EA = 1; // 是打开总中断允许
**********************************************************/
void main()
{
/*****************Y添加闪烁中断初始化**********************/
TMOD = 0x01; //是配置定时器0为16位定时模式
TH0 = 0x3C; // 设定高位初值
TL0 = 0xB0; // 设定低位初值
EA=1 ; //开启总中断
// IE = 0x82; //中断允许寄存器0x82=10000010开了总中断 ,相当于EA=1打开总中断 ;ET0=1;打开T0
/*********************************************************************/
I2C_init(); //初始化24C02
//读取低八位从24C-02的0x00读取到Num_L,高八位从0x01读取到Num_H
Num_L = AT24C_ReadByte(0);
Num_H |=AT24C_ReadByte(1)<<8; //左移8位
Set_Count = Num_H+Num_L; //高八位加上低八位
while(1)
{
Adjust();
display();
}
}
//-------------闪烁中断--------------------------
void T0_INT() interrupt 1
{
TH0 = 0x3C; // 设定低位初值
TL0 = 0xB0; // 设定高位初值
n_50ms++; // 进入中断自加
n_50ms %= 6; //10对应1Hz 取余后如果=6
if(!n_50ms)
{
flag = ~flag;
if ( num1 != Set_Count ) //设定后延时关闭闪烁
{
num2++ ;
// if( num2==3)
// { flag =0;ET0=1;TR0 = 0; num2=0 ; num1=Set_Count ;} //num2++ ;
}
}
}
复制代码
作者:
宏达工控
时间:
2023-8-9 20:31
设置了一个标志位,可以了
if ( num1 != Set_Count ) // 设定值有变化,存入24c
{
//写入数据
AT24C_WriteByte(0,Set_Count%256);
delay_ms(5) ; //显示2MS
AT24C_WriteByte(1,Set_Count/256);
delay_ms(5); //显示2MS
bc_Flag=1; //保存完成标志
num1=Set_Count ; //保存完成 将设定值送到设定值变化缓存
}
}
if( num2==3) //设定超时保存后,闪烁几次关闭闪烁
{ET0=1;TR0 = 0; num2=0 ; bc_Flag=0;flag=0;} //num2++ ;
}
//中断内
if ( bc_Flag==1 ) //设定后延时关闭闪烁
{
num2++ ;
}
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1