LCD12864串行传输数据,现在走时有问题,走时1,2秒,停上7秒钟,又走两秒在显示3,4,往后也是这样,大家看看是发送数据的问题还是DS1302的问题
#include <mega16.h>
#include <delay.h> #define uchar unsigned char
#define uint unsigned int
uchar line1[11]={' ',' ','-',' ',' ','-',' ',' ',' ',' ','\0'};//显示第1行的字符数组
uchar line2[9]={' ',' ',':',' ',' ',':',' ',' ','\0'}; //显示第2行的字符数组
uchar settime[7]={49,58,14,10,11,07,07}; //设置的秒,分,时,日,月,星期,年
uchar asc[2]={0,0};
uchar time[9]={0,0}; uchar ptTimeD[];
#define SCLK PORTA.6 并行使能端, H有效, L无效
#define SID PORTA.5 //并行读写选择信号, H读, L写
#define CS PORTA.4 //并行的指令/数据选择信号, H数据, L命令
#define SCLK_DIR DDRA.6 //并行使能端, H有效, L无效
#define SID_DIR DDRA.5 //并行读写选择信号, H读, L写
#define CS_DIR DDRA.4 //并行的指令/数据选择信号, H数据, L命令
/******************RTC常量******************/
#define RTC_CLK 4
#define RTC_DATA 3
#define RTC_CS 2
#define DDC4 4
#define DDC3 3
#define DDC2 2
//命令
#define RD 0x01
#define WR 0x00
#define C_SEC 0x80
#define C_MIN 0x82
#define C_HR 0x84
#define C_DAY 0x86
#define C_MTH 0x88
#define C_WK 0x8A
#define C_YR 0x8C
#define C_WP 0x8E
#define C_CHARGE 0x90
#define C_BURST 0xBE
//配置
#define CLK_HALT 0x80
#define CLK_START 0x00
#define M12_24 0x80
#define PROTECT 0x80
#define UPROTECT 0x00
//涓流充电控制常量
#define TC_D1R2 0xA5
#define TC_D2R8 0xAB
#define TC_DISABLED 0x00
//RAM 命令
#define C_RAMBASE 0xC2
void Delayus(uint US)
{
uint i;
US=US*5/4;
for( i=0;i<US;i++);
}
void Delayms(uint MS)
{
uint i,j;
for( i=0;i<MS;i++)
for(j=0;j<1141;j++);
}
void swrite(unsigned char dc,unsigned char da)
{
uchar i,j;
CS=1;
SCLK=0;
SID=1;
for( i=5;i>0;--i)
{
SCLK = 1;
#asm("nop");
#asm("nop");
#asm("nop");
#asm("nop");
#asm("nop");
#asm("nop");
SCLK = 0;
#asm("nop");
#asm("nop");
#asm("nop");
}
SID = 0;//数据从MCU到LCD //RW = 0;
SCLK = 1;
#asm("nop");
#asm("nop");
#asm("nop");
#asm("nop");
#asm("nop");
#asm("nop");
SCLK = 0;
if(dc) //是1的话表示传输数据
SID = 1; //RS = 1,写数据
else
SID = 0; //是0是传输指令
SCLK = 1;
#asm("nop");
#asm("nop");
#asm("nop");
#asm("nop");
SCLK = 0;
SID = 0;
SCLK = 1;
#asm("nop");
#asm("nop");
#asm("nop");
#asm("nop");
SCLK = 0;
for(i=0;i<2;i++) //数据先高后低,4位地传输
{
for(j=0;j<4;j++) //高4位数据
{
da<<=1;
SID=SREG.0; //将移出的数据送出测试
SCLK= 1;
#asm("nop");
#asm("nop");
#asm("nop");
#asm("nop");
#asm("nop");
SCLK= 0;
#asm("nop");
#asm("nop");
#asm("nop");
}
SID = 0;
for(j=0;j<4;j++ )
{
SCLK= 1;
#asm("nop");
#asm("nop");
#asm("nop");
#asm("nop");
SCLK= 0;
#asm("nop");
#asm("nop");
#asm("nop");
}
}
}
void writeString(flash uchar *aa)
{
uchar i = 0;
while(aa[i]!='\0')
{
swrite(1,aa[i++]);//数据指令
}
}
void writeString1(uchar *a)
{
uchar i = 0;
while(a[i]!='\0')
{
swrite(1,a[i++]);//数据指令
}
}
void setPosition(uchar x, uchar y)
{
uchar p;
switch(x%4)
{
case 0: p = 0x80; break; //第一行开始地址
case 1: p = 0x90; break; //第二行
case 2: p = 0x88; break; //第三行
case 3: p = 0x98; break; //第四行
}
p += y;
swrite(0,p); //位置信息指令
}
//初始化LCD
void init(void)
{
delay_ms(20);
swrite(0,0x30); //基本指令, 扩充指令为34H
delay_ms(1);
swrite(0,0x0c); //显示开, 关光标 0c ,,0d允许反白
delay_ms(1);
swrite(0,0x01); //清屏
delay_ms(10);
}
/*******************************************
函数名称: DS1302_init
功 能: 初始化DS1302的数据接口
参 数: 无
返回值 : 无
********************************************/
void DS1302_portinit(void)
{
DDRC|=(1<<DDC4)|(1<<DDC3)|(1<<DDC2);//将时钟端(RTC_CLK)数据端(RTC_DATA)片选端(RTC_CS)设置为输出
}
/*******************************************
函数名称: DS1302_writeB
功 能: 向DS1302写入一个字节数据
参 数: byte--要写入的数据
返回值 : 无
********************************************/
void DS1302_writeB(uchar byte)
{
uchar i;
for(i=0;i<8;i++)
{
PORTC&=~(1<<RTC_CLK);
if(byte&0x01)
{
PORTC|=(1<<RTC_DATA);
}
else
{
PORTC&=~(1<<RTC_DATA);
}
Delayus(20);
PORTC|=(1<<RTC_CLK);
byte>>=1;
}
}
/*******************************************
函数名称: DS1302_readB
功 能: 从DS1302读出一个字节数据(没有RST操作)
参 数: 无
返回值 : byte--读出的数据
********************************************/
uchar DS1302_readB(void)
{
uchar i,byte=0;
DDRC&=~(1<<DDC3); //将数据端口设置为输入
PORTC&=~(1<<RTC_DATA); //无上拉电阻
for(i=0;i<8;i++) //8位数据计数
{
byte>>=1; //保存读入的数据位
PORTC|=(1<<RTC_CLK); //时钟上升沿
Delayus(20); //延时,调整时钟脉冲宽度
PORTC&=~(1<<RTC_CLK); //时钟下降沿,DS1302输出数据位
Delayus(20); //等待数据变化(MEGA16太快,必须等待DS1302的数据位输出,否则不能正确读出)
if(PINC&(1<<RTC_DATA)) //当前位是否是高电平
{
byte|=(1<<RTC_CLK); //是高电平就将返回数据的当前位置1
}
else
{
byte&=~(1<<RTC_CLK); //是低电平就将返回数据的当前位置0
}
}
DDRC|=(1<<RTC_DATA); //最后将数据端口设置为输出
return byte; //返回读出的数据
}
/*******************************************
函数名称: DS1302_writeD
功 能: 向DS1302的某个地址写入一个字节数据
参 数: addr--地址值(寄存器或RAM)
data--要写入的地址
返回值 : 无
********************************************/
void DS1302_writeD(uchar addr,uchar data)
{
PORTC&=~(1<<RTC_CS); //拉低片选端
PORTC&=~(1<<RTC_CLK); //拉低时钟端
Delayus(5);
PORTC|=(1<<RTC_CS); //拉高片选端
Delayus(20); //调整片选脉冲
DS1302_writeB(addr); //写入操作命令(地址)
Delayus(20);
PORTC&=~(1<<RTC_CLK); //拉低时钟端
Delayus(20);
DS1302_writeB(data); //写入数据
PORTC&=~(1<<RTC_CLK); //拉低时钟端
Delayus(20); //调整片选脉冲
PORTC&=~(1<<RTC_CS); //拉低片选端
}
/*******************************************
函数名称: DS1302_readD
功 能: 从DS1302的某个地址读出一个字节数据
参 数: addr--地址值(寄存器或RAM)
返回值 : data--读出的数据
********************************************/
uchar DS1302_readD(uchar addr)
{
uchar data;
PORTC&=~(1<<RTC_CS); //拉低片选端
PORTC&=~(1<<RTC_CLK); //拉低时钟端
Delayus(10);
PORTC|=(1<<RTC_CS); //拉高片选端
Delayus(10); //调整片选脉冲
DS1302_writeB(addr); //写入操作命令(地址)
Delayus(10);
data=DS1302_readB(); //读出数据
Delayus(10);
PORTC&=~(1<<RTC_CLK); //拉低时钟端
PORTC&=~(1<<RTC_CS); //拉低片选端
return data; //返回读出的数据
}
/*******************************************
函数名称: DS1302_setT
功 能: 设置DS1302的时间
参 数: ptTimeD--设置时间数组指针
返回值 : 无
********************************************/
void DS1302_setT(void)
{
uchar i;
uchar addr = 0x80; //写入地址从秒寄存器开始
DS1302_writeD(C_WP|WR,UPROTECT); //控制命令,WP位为0,允许写操作
Delayms(10);
for(i=0;i<7;i++)
{
DS1302_writeD(addr|WR,ptTimeD[i]); // 秒 分 时 日 月 星期 年
addr+=2;
Delayms(20);
}
DS1302_writeD(C_WP|WR,PROTECT); //控制命令,WP位为1,不允许写操作
}
/*******************************************
函数名称: DS1302_getT
功 能: 读取DS1302的当前时间
参 数: time[]--读取的时间数组
返回值 : 无
********************************************/
void DS1302_getT(uchar time[])
{
uchar i;
////////下面的是单次读写//////////////////////////
uchar addr = 0x80; //读取地址从秒寄存器开始
for(i=0;i<7;i++)
{
time[i]=DS1302_readD(addr|RD); // 秒 分 时 日 月 星期 年
addr+=2;
}
////////////////////////////////////////////////////
/*///////下面是多字节读取///////////////
PORTC&=~(1<<RTC_CS); //拉低片选端
Delayus(10);
PORTC|=(1<<RTC_CS); //拉高片选端
Delayus(10); //调整片选脉冲
DS1302_writeB(0xbf); // 0xbf:时钟多字节读取命令
for (i=0;i<8;i++) //时间数据的存放格式是:
{ //秒,分,时,日,月,星期,年,控制
time[i]=DS1302_readB(); //【7个数据(BCD格式)+1个控制】
Delayus(10);
}
PORTC&=~(1<<RTC_CS); //拉低片选端
/////////////////////////////////////////////
*/
PORTC&=~(1<<RTC_CLK); //拉低时钟端(时钟端在不操作时为低)
}
/*******************************************
函数名称: DS1302_init
功 能: 初始化DS1302
参 数: 无
返回值 : 无
********************************************/
void DS1302_init(void)
{
DS1302_writeD(C_WP|WR,UPROTECT); //写入写允许命令
DS1302_writeD(C_SEC|WR,CLK_START); //启动振荡器,DS1302开始工作
DS1302_writeD(C_WP|WR,PROTECT); //控制命令,WP位为1,不允许写操作
}
/*******************************************
函数名称: BCD_ASCII
功 能: 将压缩BCD码转换成ascii码
参 数: BCD--将要转换的压缩BCD码
ptasc--转换后的ASCII码数组指针
返回值 : 无
********************************************/
void BCD_ASCII(uchar BCD,uchar ptasc[])
{
ptasc[0]=(BCD/16)+48; //0X58 35 38 //转换十位
ptasc[1]=(BCD&0x0F)+48; //转换个位
}
/*******************************************
函数名称: main
功 能: 1. 在1602液晶上显示当前时间 2.可以设置时间(M1-M9为数字0-9,M13为设置模式和显示模式选择,M14为当前设置位选择)
参 数: 无
返回值 : 无
********************************************/
void main(void)
{
uchar i,j;
PORTA=0x00;
DDRA=0xFF;
PORTC=0x00;
DDRC=0xFF;
init();
DS1302_portinit(); //初始化DS1302的三根数据线
DS1302_init();
DS1302_setT(); //设置初始时间
DS1302_writeD(C_SEC,0x00);//启动振荡器,DS1302开始工作
while(1) //以下程序完成显示和设置时间
{
uchar addr = 0x80;
for(j=0;j<7;j++)
{
time[j]=DS1302_readD(addr|RD); // 秒 分 时 日 月 星期 年
addr+=2;
}
for(i=0;i<3;i++) 为第2行的字符数组赋值
{
BCD_ASCII(time[2-i],asc);
line2[i*3]=asc[0];
line2[i*3+1]=asc[1];
}
BCD_ASCII(time[6],asc); //为第1行的年赋值
line1[0]=asc[0];
line1[1]=asc[1];
BCD_ASCII(time[4],asc); //为第1行的月赋值
line1[3]=asc[0];
line1[4]=asc[1];
BCD_ASCII(time[3],asc); //为第1行的日赋值
line1[6]=asc[0];
line1[7]=asc[1];
BCD_ASCII(time[5],asc); //为第1行的星期赋值
line1[9]=asc[1];
setPosition(0, 0);
writeString1(line1);
setPosition(2, 0);
writeString1(line2);
}
}
关键词:
CVAVR
写的
ds130212864
液晶
调