标题:
12864+51单片机温度显示曲线程序
[打印本页]
作者:
李清波8
时间:
2019-6-28 17:06
标题:
12864+51单片机温度显示曲线程序
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
//**********宏定义所需指令
#define BASIC_SET 0x30
#define EXTEND_SET 0x34
#define DRAW_ON 0x36
#define DRAW_OFF 0x34
//*************端口定义
sbit LCD_RS = P3^5;
sbit LCD_RW = P3^6;
sbit LCD_EN = P3^4;
sbit DQ=P2^2;
//sbit k1=P1^0;
//定义温度DS18B20接口
//************变量定义
uchar code t0[]="温度 . ℃";
uchar code t1[]="0123456789"; //利用一个温度表解决温度显示乱码
uchar i,k,a,b;
unsigned int temperature;
unsigned char temp_x; //温度小数部分
unsigned int temp_disp;
//****************短延时
void delay(uint k)
{
uint i;
uchar j;
for(i = 0; i < k ;i ++)
for(j = 120; j>0 ;j--);
}
//***********12864写指令函数
void write_com(uchar cmd)
{
LCD_RS = 0;
LCD_RW = 0;
delay(5);
LCD_EN = 1; P0 = cmd;
delay(10);
LCD_EN = 0;
}
//********12864写数据函数
void write_dat(uchar dat)
{
LCD_RS = 1;
LCD_RW = 0;
delay(5);
LCD_EN = 1; P0 = dat;
delay(10);
LCD_EN = 0;
}
//
uchar read_dat(void)
{
uchar temp;
P0 = 0XFF;
//释放数据线
LCD_RS = 1;
//数据
LCD_RW = 1;
// 读模式
LCD_EN = 1;
//E为高电平进行读数据或指令
delay(1);
temp = P0;
LCD_EN = 0;
return temp;
}
//设置光标(地址)函数
//参数说明:x---为行号,y为列号
void set_cursor(unsigned char x, unsigned char y)
{
unsigned char i;
switch(x)
//确定行号
{
case 0x00: i=0x80; break; //第一行
case 0x01: i=0x90; break; //第二行
case 0x02: i=0x88; break; //第三行
case 0x03: i=0x98; break; //第四行
default : break;
}
i = y+i; //确定列号
write_com(i);
}
//********************************************************
//显示字符函数
//********************************************************
void display_char(unsigned char Alphabet)
{
write_dat(Alphabet);
//写入需要显示字符的显示码
}
//********************************************************
//指定位置显示字符串函数
//参数说明:x为行号,y为列号
//********************************************************
void display_string(unsigned char x,unsigned char y,unsigned char *Alphabet)
{
unsigned char i=0;
set_cursor(x,y); //设置显示的起始地址
while(Alphabet[i]!='\0')
{
write_dat(Alphabet[i]); //写入需要显示字符的显示码
i++;
}
}
//以下为GDRAM绘图部分
//绘图显示的清屏函数(因清屏指令在画图时不能用)
void gui_clear()
{
uchar i , j , k;
write_com(EXTEND_SET);//扩展指令集,8位数据传输
write_com(DRAW_OFF);//绘图显示关闭
for(i = 0; i < 2; i ++)//分上下两屏写
{
for(j = 0; j < 32; j ++)
{
write_com(0x80 + j);//写y坐标
delay(1);
if(i == 0) //写x坐标
{
write_com(0x80);
delay(1);
}
else //写下半屏
{
write_com(0x88);
delay(1);
}
for(k = 0; k < 16; k ++)//写一整行数据
{
write_dat(0x00);//写高字节
write_dat(0x00);//写低字节
delay(1);
}
}
}
write_com(DRAW_ON);//打开绘图显示
write_com(BASIC_SET);//打开基本指令集
}
//(给定坐标并打点的)任意位置打点函数
void lcd_set_dot(uchar x,uchar y)
{
uchar x_byte,x_bit; //确定在坐标的那一字节哪一位
uchar y_ping , y_bit; //确定在坐标的哪一屏哪一行
uchar tmph , tmpl; //定义两个临时变量,用于存放读出来的数据
write_com(EXTEND_SET); //扩展指令集
write_com(DRAW_OFF); //绘图显示关闭
x_byte = x / 16; //算出在哪一字节,注意一个地址是16位的
x_bit = x % 16; //& 0x0f;//算出在哪一位
y_ping = y / 32; //确定在上半屏还是下半屏,0代表上半屏,1代表下半屏
y_bit = y % 32; //& 0x1f;//确定在第几行
write_com(0X80 + y_bit);//先写垂直地址(最高位必须)
write_com(0x80 + x_byte + 8 * y_ping);//水平坐标,下半屏坐标起始地址为0x88,(+8*y_ping)就是用来确定上半屏还是下半屏
read_dat();//预读取数据
tmph = read_dat();//读取当前显示高8位数据
tmpl = read_dat();//读取当前显示低8位数据
delay(1);
write_com(0x80 + y_bit);//读操作会改变AC,所以重新设置一下
write_com(0x80 + x_byte + 8 * y_ping);
delay(1);
if(x_bit < 8)
{
write_dat(tmph | (0x01 << (7 - x_bit)));//写高字节,因为坐标是从左向右的,GDRAM高位在昨,低位在右
write_dat(tmpl);//原低位数据送回
}
else
{
write_dat(tmph);//原高位数据送回
write_dat(tmpl | (0x01 << (15 - x_bit)));
}
write_com(DRAW_ON); //打开绘图显示
write_com(BASIC_SET);//回到基本指令集
}
//画水平线函数
//x0、x1为起始点和终点的水平坐标,y为垂直坐标
//**********************************************************
void gui_hline(uchar x0, uchar x1, uchar y)
{
uchar bak;//用于对两个数互换的中间变量,使x1为大值
if(x0 > x1)
{
bak = x1;
x1 = x0;
x0 = bak;
}
do
{
lcd_set_dot(x0 , y);//从左到右逐点显示
x0 ++;
}
while(x1 >= x0);
}
//***********画竖直线函数***********************************//
//x为起始点和终点的水平坐标,y0、y1为垂直坐标***************//
//**********************************************************//
void gui_rline(uchar x, uchar y0, uchar y1)
{
uchar bak;//用于对两个数互换的中间变量,使y1为大值
if(y0 > y1)
{
bak = y1;
y1 = y0;
y0 = bak;
}
do
{
lcd_set_dot(x , y0);//从上到下逐点显示
y0++;
}
while(y1 >= y0);
}
//*********任意两点间画直线*********************************//
//x0、y0为起始点坐标,x1、y1为终点坐标**********************//
//**********************************************************//
void gui_line(uchar x0 , uchar y0 , uchar x1 , uchar y1)
{
char dx; //直线x轴差值
char dy; //直线y轴差值
char dx_sym; //x轴增长方向,为-1时减值方向,为1时增值方向
char dy_sym; //y轴增长方向,为-1时减值方向,为1时增值方向
char dx_x2; //dx*2值变量,用于加快运算速度
char dy_x2; //dy*2值变量,用于加快运算速度
char di; //决策变量
if(x0 == x1)//判断是否为垂直线
{
gui_rline(x0 , y0 , y1);//画垂直线
return;
}
if(y0 == y1)//判断是否为水平线
{
gui_hline(x0 , x1 , y0);//画水平线
return;
}
dx = x1 - x0;//求取两点之间的差值
dy = y1 - y0;//****判断增长方向,或是否为水平线、垂直线、点*//
if(dx > 0)//判断x轴方向
dx_sym = 1;
else
{
if(dx < 0)
dx_sym = -1;
else
{
gui_rline(x0 , y0 , y1);
return;
}
}
if(dy > 0)//判断y轴方向
dy_sym = 1;
else
{
if(dy < 0)
dy_sym = -1;
else
{
gui_hline(x0 , x1 , y0);
return;
}
}
/*将dx、dy取绝对值***********/
dx = dx_sym * dx;
dy = dy_sym * dy;
/****计算2倍的dx、dy值*******/
dx_x2 = dx * 1;//我改为了一倍,这样才跟真实的两点对应
dy_x2 = dy * 1; /***使用bresenham法进行画直线***/
if(dx >= dy)//对于dx>=dy,使用x轴为基准
{
di = dy_x2 - dx;
while(x0 != x1)
{
lcd_set_dot(x0,y0);
x0 +=dx_sym;
if(di < 0)
di += dy_x2;//计算出下一步的决策值
else
{
di += dy_x2 - dx_x2;
y0 += dy_sym;
}
}
lcd_set_dot(x0, y0);//显示最后一点
}
else //对于dx<dy使用y轴为基准
{
di = dx_x2 - dy;
while(y0 != y1)
{
lcd_set_dot(x0, y0);
y0 += dy_sym;
if(di < 0)
di += dx_x2;
else
{
di += dx_x2 - dy_x2;
x0 += dx_sym;
}
}
lcd_set_dot(x0, y0);//显示最后一点
}
}
//以上为自定义字库部分
//****************12864初始化函数
void lcd_init()
{
write_com(0x30);//基本指令操作,8位并口
delay(1);
write_com(0x0c);//设置为游标右移,DDRAM地址加一,画面不动
delay(1);
write_com(0x01);//显示开,关光标
delay(1);
write_com(0x06);//清除lcd显示内容
delay(1);
} //5ms延时
void Delay5Ms(void)
{
unsigned int TempCyc = 5552;
while(TempCyc--);
}
//400ms延时
void Delay400Ms(void)
{
unsigned char TempCycA = 5;
unsigned int TempCycB;
while(TempCycA--)
{
TempCycB=7269;
while(TempCycB--);
};
}
/*************DS18B20温度读取模块*************/
void delay_nus(unsigned char n)
{
while(n--)
{
_nop_();
_nop_();
}
}
bit ds18b20_reset(void)
{
CY = 1;
while(CY)
{
DQ = 0; //送低电平复位信号
delay_nus(240); //至少延时480us
delay_nus(240);
DQ = 1; //释放数据线
delay_nus(60); //等待60us
CY = DQ; //检测存在脉冲
delay_nus(240); //等待设备释放数据线
delay_nus(180);
}
return 1;
}
unsigned char ds18b20_readbyte(void)
{
unsigned char i;
unsigned char dat = 0;
for(i=0;i<8;i++)
{
dat >>= 1;
DQ = 0; //开始时间片
delay_nus(1); //延时等待
DQ = 1; //准备接收
delay_nus(1); //延时
if(DQ) dat |= 0x80; //读取数据
delay_nus(60); //等待时间片结束
}
return dat;
}
void ds18b20_writebyte(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
delay_nus(1);
dat >>= 1;
DQ = CY;
delay_nus(60);
DQ = 1;
delay_nus(1);
}
}
void read_temp(void)
{
if(ds18b20_reset())
{
ds18b20_writebyte(0xcc);
ds18b20_writebyte(0x44);
if(ds18b20_reset())
{
ds18b20_writebyte(0xcc);
ds18b20_writebyte(0xbe);
temperature = ds18b20_readbyte(); //读温度整数值
temperature = (ds18b20_readbyte() << 8) + temperature;
temp_x = (unsigned char)(temperature & 0x000f); //读温度小数值
temp_x = (unsigned char)(((unsigned int)temp_x * 625) / 1000);
temperature >>= 4;
temp_disp = temperature * 10 + temp_x;
}
}
}
//*****************************显示函数
void display()
{
uint num;
uint shi,ge,xiaoshu;
num=temp_disp;
shi=num/100;
ge=num/10%10;
xiaoshu=num%10;
if(k==100)
{
++i;
k=0;
if(i>127)
{
i=0;
a=0;
b=0;
gui_clear();//画图时清屏函数
gui_line(0,15,0,63);
gui_line(0,63,127,63);
}
gui_line(a,63-b,i,63-shi*10-ge);
b=shi*10+ge;
a=i;
}
write_com(0x82);
write_dat(t1[shi]);
write_dat(t1[ge]);
write_com(0x84);
write_dat(t1[xiaoshu]);
}
void init_time0()
{
TMOD |= 0x10;
TH1=(65536-50000)/256; //50毫秒
TL1=(65536-50000)%256;
EA=1;
ET1=1;
TR1=1;
}
void main()
{
init_time0(); //中断
lcd_init();//12864初始化函数
gui_clear();//画图时清屏函数
delay(10);
display_string(0,0,t0);
gui_line(0,15,0,63);
gui_line(0,63,127,63);
while(1)
{
display();read_temp();
}
}
void time0() interrupt 3
{
TH1=(65536-50000)/256; //,50毫秒
TL1=(65536-50000)%256;
k++;
}
复制代码
12864温度有线.rar
2019-6-28 17:06 上传
点击文件名下载附件
下载积分: 黑币 -5
109.3 KB, 下载次数: 46, 下载积分: 黑币 -5
51单片机温度显示曲线
作者:
admin
时间:
2019-6-28 18:07
本帖需要重新编辑补全电路原理图,源码,详细说明与图片即可获得100+黑币(帖子下方有编辑按钮)
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1