单片机与控制实验(5)——重量测量并在LCD12864显示
本文为大大维原创,最早于博客园发表,转载请注明出处!!!
一、实验目的和要求
掌握点阵式液晶显示屏的原理和控制方法,掌握点阵字符的显示方法。
掌握模拟/数字(A/D)转换方式,
进一步掌握使用C51语言编写程序的方法,使用C51语言编写实现重量测量的功能。
二、实验设备
单片机测控实验系统
重量测量实验板/砝码
Keil开发环境
STC-ISP程序下载工具
三、实验内容
编写C51程序,使用重量测量实验板测量标准砝码的重量,将结果(以克计)显示到液晶屏上。误差可允许的范围之间。
四、实验步骤
1. 阅读实验原理,掌握YM12864C的控制方式,编写出基本的输出命令和数据的子程序;
2. 掌握点阵字模的构成方式。使用字模软件PCtoLCD2002,设定正确的输出模式,生成点阵数据;
3. 使用C51语言编写重量测量程序;
4. 调零,满量程校准;
5. 将编译后的程序下载到51单片机;
6. 在托盘中放上相应重量的法码,使显示值为正确重量。
五、实验原理
1. 参考下文,学习点阵式液晶显示屏的控制方法。
2. 在液晶显示中,自定义图形和文字的字模对应的字节表需要使用专门的字模软件来生成。可以使用PCtoLCD2002字模软件提取。
3. 字符点阵等数据,需要定义在code数据段中,具体原理参见示例程序设计部分。
4. 向LCM输出一个命令或数据时,应当在选通信号为高时准备好数据,然后延迟若干指令周期,再将选通信号置为低。
5. 与A/D转换相关的寄存器
ADC_POWER:ADC电源控制位,0关1开。
SPEED1,SPEED0:模数转换器速度控制位,控制A/D转换所需时间。
ADC_FLAG:模数转换结束标志位,AD转换完后,ADC_FLAG=1,一定要软件清0。
ADC_START:模数转换器(ADC)转换启动控制位,1开始转换,转换结束后为0。
CHS2/CHS1/CHS0:模拟输入通道选择,选择使用P1.0~P1.7作为A/D输入。
ADC_RES、ADC_RESL: A/D转换结果寄存器,是特殊功能寄存器,用于保存A/D转换结果。
IE:中断允许寄存器(可位寻址)
EA:CPU的中断开放标志,EA=1,CPU开放中断,EA=0,CPU屏蔽所有中断申请。
EADC:A/D转换中断允许位。1允许0禁止。
IPH:中断优先级控制寄存器高(不可位寻址)。
IP:中断优先级控制寄存器低(可位寻址)。
A/D转换器的具体使用方法参见STC单片机指南的第九章。
6. 重量传感器采用压敏电阻。利用压敏电阻采集应变,产生变化的阻值。利用放大电路将其转化为电压值,通过数模转换将电压值转化成CPU处理的数字信号。传感器根据编制的程序将数字信号转换为砝码重量显示输出。
7.本实验示意电路原理图:
六、实验代码
#include<reg52.h>
#include<intrins.h> // 声明了void _nop_(void)
#define LcdData P2 //LCD数据口(8线接法)
typedef unsigned int uint;
typedef unsigned char uchar; //*************AD端口定义及相关函数声明**************
sfr PLASF = 0X9D; //P1口模拟功能控制寄存器P1ASF
sfr ADC_CONTR = 0XBC; //ADC控制寄存器
sfr ADC_RES = 0XBD; //A/D转换结果寄存器高
sfr ADC_RESL = 0XBE; //A/D转换结果寄存器低
sfr AUXR1 = 0XA2;
sfr IPH = 0XB7; //中断优先级控制寄存器高
bit EADC = 0XA8^; //A/D转换中断允许位
#define ADC_POWER 0X80 //ADC电源控制位
#define ADC_FLAG 0X10 //模数转换器(ADC)转换启动控制位
#define ADC_START 0X08
#define ADC_SPEEDLL 0X00
#define ADC_SPEEDL 0X20
#define ADC_SPEEDH 0X40
#define ADC_SPEEDHH 0X60 //AD函数声明
uint ADC_GET(uchar n); //获得ADCData
void DelayMs(uint n); //软件延迟n毫秒
void InitAD(uchar n); //AD初始化
void DelayUs(uint cnt); //延时cnt us(NOP) //*********LCD端口定义及相关函数声明***************
sbit RST = P1^;
sbit CS1 = P1^; //左半屏选择
sbit CS2 = P1^; //右半屏选择
sbit E = P3^; //使能
sbit RW = P3^ ; //读/写选择器引脚(R/W)
sbit RS = P3^; //数据/命令选择器引脚(R/S)
sbit BUSY = P2^; //BUSY位
uchar mypage=; //汉字显示页设置
//C51并不支持位数组
//sbit DB[] = {P2^0, P2^1, P2^2, P2^3, P2^4, P2^5, P2^6, P2^7}; //LCD函数声明
void LcdCommandWrite(uchar value); //写指令代码函数
void LcdDataWrite(uchar value); //写显示数据函数
void LcdCommandRead(void); //读状态字函数
//void LcdDataRead(void); //读显示数据函数
//C51中没有布尔类型
void IsBusy(void); //读状态字时判断BUSY是否为1
void ShowOn(void); //显示开
void ShowOff(void); //显示关
void SetRow(uchar row); //设置显示行
void SetCol(uchar col); //设置显示列
void SetPage(uchar page); //设置显示页
void ScreenChoose(uint screen); //屏幕显示选择
void Clear(uint screen); //清选定的屏
void DisplayWord(uint screen,uchar page,uchar col,uchar *word); //显示汉字,按页显示
void DisplayChar(uint screen,uchar row,uchar col); //显示字符,按行显示
void Display(uint weight); //重量显示
void Delay(uint cnt); //延迟函数
void DisplayLine(void); //显示一条直线
void InitLCD(void); //LCD初始化 //*********LCD字码***************
uchar code zhong[]={0x10,0x10,0x14,0xD4,0x54,0x54,0x54,0xFC,0x52,0x52,0x52,0xD3,0x12,0x10,0x10,0x00,0x40,0x40,0x50,0x57,0x55,0x55,0x55,0x7F,0x55,0x55,0x55,0x57,0x50,0x40,0x40,0x00};
uchar code liang[]={0x20,0x20,0x20,0xBE,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xBE,0x20,0x20,0x20,0x00,0x00,0x80,0x80,0xAF,0xAA,0xAA,0xAA,0xFF,0xAA,0xAA,0xAA,0xAF,0x80,0x80,0x00,0x00};
uchar code wei[]={0x00,0x20,0x22,0x2C,0x20,0x20,0xE0,0x3F,0x20,0x20,0x20,0x20,0xE0,0x00,0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x06,0x01,0x00,0x01,0x46,0x80,0x40,0x3F,0x00,0x00,0x00};
uchar code maohao[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar code ling[]={0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar code yi[]={0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar code er[]={0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar code san[]={0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar code si[]={0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar code wu[]={0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar code liu[]={0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar code qi[]={0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar code ba[]={0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar code jiu[]={0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar code ke[]={0x04,0x04,0xE4,0x24,0x24,0x24,0x24,0x3F,0x24,0x24,0x24,0x24,0xE4,0x04,0x04,0x00,0x80,0x80,0x43,0x22,0x12,0x0E,0x02,0x02,0x02,0x7E,0x82,0x82,0x83,0x80,0xE0,0x00}; //*********main函数***************
void main()
{
InitAD();
InitLCD();
DisplayLine();
while()
{
uint ad = ;
ad = ADC_GET();
Display(ad);
}
} //*********AD函数定义***************
void InitAD(uchar n)
{ PLASF = 0xff;
ADC_RES = ;
ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
DelayMs(); n &= 0x07;
AUXR1 |= 0x04;
PLASF = <<n; PLASF = 0X01;
ADC_CONTR = 0X10;
EA = ;
ADC_RES = 0X00;
ADC_RESL = 0X00;
EADC = ; //AD中断开 }
uint ADC_GET(uchar n)
{ uint ADCData;
n &= 0x07;
ADC_RES = ;
ADC_RESL = ;
ADC_CONTR = ; //ADC_CONTR置0
ADC_CONTR |= (ADC_POWER|ADC_SPEEDLL|n|ADC_START);
DelayUs(); //延迟6个nop,书上4个nop,不够
while(!((ADC_CONTR & ADC_FLAG) == 0x10))
ADCData = (ADC_RES&0x03)* + ADC_RESL; //取十位结果
return ADCData-(+); //返回ADCData
} void DelayMs(uint n)
{
uint x;
while(n--)
{
x = ;
while(x--);
}
} //*********LCD函数定义***************
void InitLCD(void)
{
IsBusy();
RST=;
RST=; //复位
Delay();
RST=;
ShowOff();
Delay();
ShowOn();
Clear();
//设置起始位置(0,0)
SetPage();
SetRow();
SetCol();
}
void ScreenChoose(uint screen){
switch(screen)
{
case : CS1=;CS2=;break; //全屏
case : CS1=;CS2=;break; //左屏
case : CS1=;CS2=;break; //右屏
default: CS1=;CS2=;break; //全屏
}
} void LcdCommandWrite(uchar value) //写指令代码函数
{
IsBusy();
// 定义相关引脚
//CS1=1;
//CS2=1;
RS=;
RW=;
LcdData=value;
//一个下跳沿
E=;
Delay();
E=;
}
void LcdDataWrite(uchar value) //写显示数据函数
{
IsBusy();
//CS1=1;
//CS2=1;
RS=;
RW=;
LcdData=value;
E=;
Delay();
E=;
}
void LcdCommandRead(void) //读状态字函数
{
RS=;
RW=;
E=;
}
/*
void LcdDataRead(void) //读显示数据函数
{
RS=1;
RW=1;
E=1;
}
*/
void IsBusy(void) //判断BUSY是否为1
{
LcdCommandRead();
while(BUSY);
E=; //控制LCM读取结束
}
void DelayUs(uint cnt)
{
uint temp=;
for(temp=;temp<cnt;temp++)
/*
*对于延时很短的,要求在us级的,采用“_nop_”函数,这个函数相当汇编NOP指令,延时几微秒。
*NOP指令为单周期指令,可由晶振频率算出延时时间,对于12M晶振,延时1uS。
*/
_nop_();
}
void Delay(uint cnt)
{
while(--cnt);
}
void ShowOn(void) //显示开
{
LcdCommandWrite(0x3f);
}
void ShowOff(void) //显示关
{
LcdCommandWrite(0x3e);
}
void SetRow(uchar row) //设置显示行
{
row=row&0x3f; //Row范围0到63,高两位清零
LcdCommandWrite(0xc0+row);
}
void SetCol(uchar col) //设置显示列
{
col=col&0x3f; //Col范围0到63,高两位清零
LcdCommandWrite(0x40+col);
}
void SetPage(uchar page) //设置显示页
{
page=page&0x07; //Page范围0到7,取低三位
LcdCommandWrite(0xb8+page);
}
void Clear(uint screen){
uint i,j;
ScreenChoose(screen);
for(i=;i<;i++){
SetPage(i);
SetCol(0x00);
for(j=;j<;j++){
LcdDataWrite(0x00);
}
}
}
void DisplayWord(uint screen,uchar page,uchar col,uchar *word) //显示汉字,按页显示
{
uint i=;
//显示汉字,16*16,需要两页
ScreenChoose(screen);
SetPage(page); //选上半字
SetCol(col); //选定列数
for(i=;i<;i++){ //上半个字s
LcdDataWrite(word[i]);
}
SetPage(page+); //选下半字
SetCol(col); //选定列数
for(i=;i<;i++){ //下半个字
LcdDataWrite(word[i+]);
}
} void DisplayChar(uint screen,uchar row,uchar col) //显示字符,按行显示
{
ScreenChoose(screen);
SetRow(row); //选定行数
SetCol(col); //选定列数
LcdDataWrite(0x01);
} void Display(uint weight){ uchar a,b,c;
DisplayWord(,mypage,*,zhong); //重
DisplayWord(,mypage,*,liang); //量
DisplayWord(,mypage,*,wei); //为
DisplayWord(,mypage,*,maohao); //:
a = weight/;
b = weight%/;
c = weight%;
switch(a){
case : DisplayWord(,mypage,*,ling);break;
case : DisplayWord(,mypage,*,yi);break;
case : DisplayWord(,mypage,*,er);break;
case : DisplayWord(,mypage,*,san);break;
case : DisplayWord(,mypage,*,si);break;
case : DisplayWord(,mypage,*,wu);break;
case : DisplayWord(,mypage,*,liu);break;
case : DisplayWord(,mypage,*,qi);break;
case : DisplayWord(,mypage,*,ba);break;
case : DisplayWord(,mypage,*,jiu);break;
}
switch(b){
case : DisplayWord(,mypage,*,ling);break;
case : DisplayWord(,mypage,*,yi);break;
case : DisplayWord(,mypage,*,er);break;
case : DisplayWord(,mypage,*,san);break;
case : DisplayWord(,mypage,*,si);break;
case : DisplayWord(,mypage,*,wu);break;
case : DisplayWord(,mypage,*,liu);break;
case : DisplayWord(,mypage,*,qi);break;
case : DisplayWord(,mypage,*,ba);break;
case : DisplayWord(,mypage,*,jiu);break;
}
switch(c){
case : DisplayWord(,mypage,*,ling);break;
case : DisplayWord(,mypage,*,yi);break;
case : DisplayWord(,mypage,*,er);break;
case : DisplayWord(,mypage,*,san);break;
case : DisplayWord(,mypage,*,si);break;
case : DisplayWord(,mypage,*,wu);break;
case : DisplayWord(,mypage,*,liu);break;
case : DisplayWord(,mypage,*,qi);break;
case : DisplayWord(,mypage,*,ba);break;
case : DisplayWord(,mypage,*,jiu);break;
}
DisplayWord(,mypage,*,ke);
Delay();
}
void DisplayLine(void) //显示一条直线
{
DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,); DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,); DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,); DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,); DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,); DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,); DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,); DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,); DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,); DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,); DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,); DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,); DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,); DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,); DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,); DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,);
DisplayChar(,,);
}
七、一点想法
LCD12864控制输出时,注意行、列、页之间的 关系。
使用_nop_()函数可以精确控制延迟时间。
八、附录
STC单片机指南:点此查看
实验电路原理图:点击查看
单片机与控制实验(5)——重量测量并在LCD12864显示的更多相关文章
- 单片机与控制实验(2)——LED点阵显示屏
一.实验目的和要求 了解LED点阵显示的基本原理和实现方法.掌握点阵汉字库的编码和从标准字库中提取汉字编码的方法. 二.实验设备 单片机测控实验系统 LED点阵显示器实验模块 Keil开发环境 STC ...
- CAN-bus接口控制实验
CAN-bus接口控制实验 2016-04-12 20:38:41来源: eefocus 关键字:CAN bus 接口控制 收藏 评论(0) 分享到 微博 QQ 微信 LinkedIn 一.实 ...
- BeagleBone Black板第四课:简单LED控制实验
BBB板第四课:简单LED控制实验 学习BBB板的终于目的是想像单片机一样做控制,但控制思路全然不一样(Linux下控制硬件设备实质就是对相关设备虚拟文件的读写).研究了几天头都大了还是没有进展,网上 ...
- 安卓Socket连接实现连接实现发送接收数据,openwrt wifi转串口连接单片机实现控制
安卓Socket连接实现连接实现发送接收数据,openwrt wifi转串口连接单片机实现控制 socket 连接采用流的方式进行发送接收数据,采用thread线程的方式. 什么是线程? 详细代码介 ...
- 微型计算机系统实验总结(学习性实验:IO地址译码,可编程并行接口8255,交通灯控制实验 + 自主设计实验:汽车信号灯控制系统,电风扇控制器,洗衣机控制系统,霓虹灯,电梯控制系统)
实验配套软件: https://download.csdn.net/download/qq_39932172/11221584 实验指导用书: 教师版: https://download.csdn.n ...
- 【MM系列】SAP MM模块-控制采购订单中某些项目的输出显示
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP MM模块-控制采购订单中某些 ...
- 51单片机 | 模拟PWM调制控制实验
———————————————————————————————————————————— PWM(脉冲宽度调制) 对模拟信号电平进行数字编码的方法 - - - - - - - - - - - - - ...
- 磁钉导航差速式AGV控制实验
磁钉导航AGV实验 2016-03 本机器是采用RFID电子地标配合磁钉传感器的定位导航AGV.本AGV已初步实现里程计精确解算,磁钉数据融合,AGV定点精准停车.原地旋转换向.远程无线调度的功能,初 ...
- Mininet实验 基于Mininet测量路径的损耗率
实验原理 在SDN环境中,控制器可以通过对交换机下发流表操作来控制交换机的转发行为,此外,还可以利用控制器测量路径的损耗率.在本实验中,基于Mininet脚本,设置特定的交换机间的路径损耗速率,然后编 ...
随机推荐
- Windows 安装JRuby 生成 war 到 tomcat 运行
Windows安装JRuby Rails 直接下载 JRuby,不装 Ruby. http://jruby.org/download 该安装包可以配好环境变量 %JRUBY_HOME% 等 安装 bu ...
- WebApp开发之--"rem"单位
随着web app的兴起,rem这是个低调的css单位,近一两年开始崭露头角,有许多朋友对于它的评价不一,有的在尝试使用,有的在使用过程中遇到坑就弃用了.但是我认为rem是用来做web app它绝对是 ...
- Angularjs2 入门
1.创建文件夹 mkdir angular2-app cd angular2-app 2.配置Typescript 需要通过一些特殊的设置来指导Typesript进行编译.新建一个 tsconfig. ...
- AM335x tscadc platform driver 相关代码跟踪
TI AM335x ti am335x_tsc.c 代码跟踪 在kernel 首层目录: 先运行make ARCH=arm tags 这个作用是建立tags文件,只含有arm架构的,利用ctag即可进 ...
- MDI窗体容器--2016年12月15日
MDI窗体容器 多文档界面(Multiple-Document Interface)简称MDI窗体.MDI窗体用于同时显示多个文档,每个文档显示在各自的窗口中.MDI窗体中通常有包含子菜单的窗口菜单, ...
- django test
django的单元测试 官方文档:https://docs.djangoproject.com/en/dev/topics/testing/ 相对于自己封装urllib/urllib2/request ...
- FWT与High dick(划掉改成Dimensional) Fourier Transform
我们大家都知道xor卷积有个很好的做法:FWT.FWT的变换形式是很好看的 // 说明一下Vector可以向量化运算,也可以当做数组来slice与concat Vector tf(A,2^n){ Ve ...
- 得到 window.open 新页面中的数据
1.htm 页面 单击按 '钮后' 调用window.open方法,开启新窗口 2.htm 想实现---------------------- 在2.htm页面单击按钮 将相应的数据返回到 1. ...
- SQL排序问题
''按多个字段排序 Select * From Job order by job desc,id asc ''按首字符(非数字)排序 )) ) end ''按首字符分组 ) ''合并Order by排 ...
- mysql 分页查询
mysql,; : mysql,; -last. //如果只给定一个参数,它表示返回最大的记录行数目: mysql; 个记录行 ,n. 动态传参的分页查询 SELECT * FROM table LI ...