单片机与控制实验(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.本实验示意电路原理图:

六、实验代码  

  1 #include<reg52.h>
  2 #include<intrins.h>         // 声明了void _nop_(void)
  3 #define LcdData P2            //LCD数据口(8线接法)
  4 typedef unsigned int uint;
  5 typedef unsigned char uchar;
  6 
  7 
  8 //*************AD端口定义及相关函数声明**************
  9 sfr PLASF = 0X9D;            //P1口模拟功能控制寄存器P1ASF
 10 sfr ADC_CONTR = 0XBC;        //ADC控制寄存器
 11 sfr ADC_RES = 0XBD;            //A/D转换结果寄存器高
 12 sfr ADC_RESL = 0XBE;        //A/D转换结果寄存器低
 13 sfr AUXR1 = 0XA2;
 14 sfr IPH = 0XB7;                //中断优先级控制寄存器高
 15 bit EADC = 0XA8^5;            //A/D转换中断允许位
 16 #define ADC_POWER    0X80    //ADC电源控制位
 17 #define ADC_FLAG    0X10    //模数转换器(ADC)转换启动控制位
 18 #define ADC_START    0X08
 19 #define ADC_SPEEDLL    0X00
 20 #define ADC_SPEEDL    0X20    
 21 #define ADC_SPEEDH    0X40
 22 #define ADC_SPEEDHH    0X60
 23 
 24 //AD函数声明
 25 uint ADC_GET(uchar n);        //获得ADCData
 26 void DelayMs(uint n);        //软件延迟n毫秒
 27 void InitAD(uchar n);        //AD初始化
 28 void DelayUs(uint cnt);        //延时cnt us(NOP)
 29 
 30 //*********LCD端口定义及相关函数声明***************
 31 sbit RST = P1^5;
 32 sbit CS1 = P1^7;               //左半屏选择
 33 sbit CS2 = P1^6;               //右半屏选择
 34 sbit E = P3^3;                 //使能
 35 sbit RW = P3^4 ;              //读/写选择器引脚(R/W)
 36 sbit RS = P3^5;                //数据/命令选择器引脚(R/S)
 37 sbit BUSY = P2^7;            //BUSY位
 38 uchar mypage=2;                //汉字显示页设置
 39 //C51并不支持位数组
 40 //sbit DB[] = {P2^0, P2^1, P2^2, P2^3, P2^4, P2^5, P2^6, P2^7};
 41     
 42 //LCD函数声明
 43 void LcdCommandWrite(uchar value);    //写指令代码函数
 44 void LcdDataWrite(uchar value);        //写显示数据函数
 45 void LcdCommandRead(void);            //读状态字函数
 46 //void LcdDataRead(void);            //读显示数据函数
 47 //C51中没有布尔类型
 48 void IsBusy(void);                    //读状态字时判断BUSY是否为1
 49 void ShowOn(void);                    //显示开
 50 void ShowOff(void);                    //显示关
 51 void SetRow(uchar row);                //设置显示行
 52 void SetCol(uchar col);                //设置显示列
 53 void SetPage(uchar page);            //设置显示页
 54 void ScreenChoose(uint screen);        //屏幕显示选择
 55 void Clear(uint screen);            //清选定的屏
 56 void DisplayWord(uint screen,uchar page,uchar col,uchar *word);            //显示汉字,按页显示
 57 void DisplayChar(uint screen,uchar row,uchar col);                        //显示字符,按行显示
 58 void Display(uint weight);            //重量显示
 59 void Delay(uint cnt);                //延迟函数
 60 void DisplayLine(void);                //显示一条直线
 61 void InitLCD(void);                    //LCD初始化
 62 
 63 
 64 //*********LCD字码***************
 65 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};
 66 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};
 67 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};
 68 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};
 69 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};
 70 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};
 71 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};
 72 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};
 73 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};
 74 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};
 75 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};
 76 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};
 77 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};
 78 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};
 79 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};
 80 
 81 
 82 //*********main函数***************
 83 void main()
 84 {
 85     InitAD(0);
 86     InitLCD();
 87     DisplayLine();
 88     while(1)
 89     {
 90         uint ad = 0;
 91         ad = ADC_GET(0);
 92         Display(ad);
 93     }
 94 }
 95 
 96 //*********AD函数定义***************
 97 void InitAD(uchar n)
 98 { 
 99  
100     PLASF = 0xff;  
101     ADC_RES = 0;
102     ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
103     DelayMs(2);    
104 
105 
106     n &= 0x07;        
107     AUXR1 |= 0x04;       
108     PLASF = 1<<n;        
109 
110     PLASF = 0X01;   
111     ADC_CONTR = 0X10;
112     EA = 1;
113     ADC_RES = 0X00;
114     ADC_RESL = 0X00;
115     EADC = 1;                                       //AD中断开
116 
117 }
118 uint ADC_GET(uchar n)
119 {
120     
121     uint ADCData;
122     n &= 0x07;            
123     ADC_RES = 0;        
124     ADC_RESL = 0;        
125     ADC_CONTR = 0;                                //ADC_CONTR置0
126     ADC_CONTR |= (ADC_POWER|ADC_SPEEDLL|n|ADC_START);
127     DelayUs(6);                                    //延迟6个nop,书上4个nop,不够
128     while(!((ADC_CONTR & ADC_FLAG) == 0x10))       
129     ADCData = (ADC_RES&0x03)*256 + ADC_RESL;      //取十位结果
130     return ADCData-(636+99);                      //返回ADCData
131 }
132 
133 
134 void DelayMs(uint n)
135 {
136     uint x;
137     while(n--)
138     {
139         x = 5000;
140         while(x--);
141     }
142 }
143 
144 //*********LCD函数定义***************
145 void InitLCD(void)
146 { 
147     IsBusy();
148     RST=1;
149     RST=0;                                //复位
150     Delay(100);
151     RST=1;
152     ShowOff();
153     Delay(100);
154     ShowOn();
155     Clear(0);
156     //设置起始位置(0,0)
157     SetPage(0);
158     SetRow(0);                    
159     SetCol(0);    
160 }
161 void ScreenChoose(uint screen){
162     switch(screen)
163     {
164         case 0: CS1=1;CS2=1;break;         //全屏
165         case 1: CS1=1;CS2=0;break;         //左屏
166         case 2: CS1=0;CS2=1;break;         //右屏
167         default: CS1=1;CS2=1;break;        //全屏
168     }
169 }
170 
171 void LcdCommandWrite(uchar value)        //写指令代码函数
172 {    
173     IsBusy();
174     // 定义相关引脚
175     //CS1=1;
176     //CS2=1;
177     RS=0;
178     RW=0;
179     LcdData=value;
180     //一个下跳沿
181     E=1;
182     Delay(200);
183     E=0;
184 }
185 void LcdDataWrite(uchar value)            //写显示数据函数
186 {
187     IsBusy();
188     //CS1=1;
189     //CS2=1;
190     RS=1;
191     RW=0;
192     LcdData=value;
193     E=1;
194     Delay(200);
195     E=0;
196 }
197     void LcdCommandRead(void)            //读状态字函数
198     {    
199     RS=0;
200     RW=1;
201     E=1;
202 }
203 /*
204 void LcdDataRead(void)                    //读显示数据函数
205 {
206     RS=1;
207     RW=1;
208     E=1;
209 }
210 */
211 void IsBusy(void)                       //判断BUSY是否为1
212 {
213     LcdCommandRead();
214     while(BUSY);
215     E=0;                                //控制LCM读取结束        
216 }
217 void DelayUs(uint cnt)
218 {
219     uint temp=0;
220     for(temp=0;temp<cnt;temp++)
221     /*
222     *对于延时很短的,要求在us级的,采用“_nop_”函数,这个函数相当汇编NOP指令,延时几微秒。
223     *NOP指令为单周期指令,可由晶振频率算出延时时间,对于12M晶振,延时1uS。
224     */
225         _nop_();
226 }
227 void Delay(uint cnt)
228 {
229     while(--cnt);
230 }
231 void ShowOn(void)                        //显示开
232 {
233     LcdCommandWrite(0x3f);    
234 }
235 void ShowOff(void)                        //显示关
236 {
237     LcdCommandWrite(0x3e);    
238 }
239 void SetRow(uchar row)                    //设置显示行
240 {
241     row=row&0x3f;                        //Row范围0到63,高两位清零
242     LcdCommandWrite(0xc0+row);
243 }
244 void SetCol(uchar col)                    //设置显示列
245 {
246     col=col&0x3f;                        //Col范围0到63,高两位清零
247     LcdCommandWrite(0x40+col);
248 }
249 void SetPage(uchar page)                //设置显示页
250 {
251     page=page&0x07;                        //Page范围0到7,取低三位
252     LcdCommandWrite(0xb8+page);
253 }
254 void Clear(uint screen){
255     uint i,j;
256     ScreenChoose(screen);
257     for(i=0;i<8;i++){
258         SetPage(i);
259         SetCol(0x00);
260         for(j=0;j<64;j++){
261             LcdDataWrite(0x00);
262         }
263     }
264 }
265 void DisplayWord(uint screen,uchar page,uchar col,uchar *word)                    //显示汉字,按页显示
266 {
267     uint i=0;
268     //显示汉字,16*16,需要两页
269     ScreenChoose(screen);
270     SetPage(page);                         //选上半字
271     SetCol(col);                         //选定列数
272     for(i=0;i<16;i++){                     //上半个字s
273         LcdDataWrite(word[i]);
274     }
275     SetPage(page+1);                       //选下半字
276     SetCol(col);                         //选定列数
277     for(i=0;i<16;i++){                     //下半个字
278         LcdDataWrite(word[i+16]);
279     }
280 }
281 
282 void DisplayChar(uint screen,uchar row,uchar col)                                //显示字符,按行显示
283 {
284     ScreenChoose(screen);
285     SetRow(row);                         //选定行数
286     SetCol(col);                         //选定列数
287     LcdDataWrite(0x01);
288 }
289 
290 
291 void Display(uint weight){
292 
293     uchar a,b,c;
294     DisplayWord(1,mypage,0*16,zhong);        //
295     DisplayWord(1,mypage,1*16,liang);        //
296     DisplayWord(1,mypage,2*16,wei);            //
297     DisplayWord(1,mypage,3*16,maohao);      //:
298     a = weight/100;
299     b = weight%100/10;
300     c = weight%10;
301     switch(a){
302         case 0: DisplayWord(2,mypage,0*16,ling);break;
303         case 1: DisplayWord(2,mypage,0*16,yi);break;
304         case 2: DisplayWord(2,mypage,0*16,er);break;
305         case 3: DisplayWord(2,mypage,0*16,san);break;
306         case 4: DisplayWord(2,mypage,0*16,si);break;
307         case 5: DisplayWord(2,mypage,0*16,wu);break;
308         case 6: DisplayWord(2,mypage,0*16,liu);break;
309         case 7: DisplayWord(2,mypage,0*16,qi);break;
310         case 8: DisplayWord(2,mypage,0*16,ba);break;
311         case 9: DisplayWord(2,mypage,0*16,jiu);break;
312     }
313     switch(b){
314         case 0: DisplayWord(2,mypage,1*16,ling);break;
315         case 1: DisplayWord(2,mypage,1*16,yi);break;
316         case 2: DisplayWord(2,mypage,1*16,er);break;
317         case 3: DisplayWord(2,mypage,1*16,san);break;
318         case 4: DisplayWord(2,mypage,1*16,si);break;
319         case 5: DisplayWord(2,mypage,1*16,wu);break;
320         case 6: DisplayWord(2,mypage,1*16,liu);break;
321         case 7: DisplayWord(2,mypage,1*16,qi);break;
322         case 8: DisplayWord(2,mypage,1*16,ba);break;
323         case 9: DisplayWord(2,mypage,1*16,jiu);break;
324     }
325     switch(c){
326         case 0: DisplayWord(2,mypage,2*16,ling);break;
327         case 1: DisplayWord(2,mypage,2*16,yi);break;
328         case 2: DisplayWord(2,mypage,2*16,er);break;
329         case 3: DisplayWord(2,mypage,2*16,san);break;
330         case 4: DisplayWord(2,mypage,2*16,si);break;
331         case 5: DisplayWord(2,mypage,2*16,wu);break;
332         case 6: DisplayWord(2,mypage,2*16,liu);break;
333         case 7: DisplayWord(2,mypage,2*16,qi);break;
334         case 8: DisplayWord(2,mypage,2*16,ba);break;
335         case 9: DisplayWord(2,mypage,2*16,jiu);break;
336     }
337     DisplayWord(2,mypage,3*16,ke);
338     Delay(5000);
339 }
340 void DisplayLine(void)                    //显示一条直线
341 {
342     DisplayChar(1,50,0);
343     DisplayChar(1,50,1);
344     DisplayChar(1,50,2);
345     DisplayChar(1,50,3);
346     
347     DisplayChar(1,50,8);
348     DisplayChar(1,50,9);
349     DisplayChar(1,50,10);
350     DisplayChar(1,50,11);
351     
352     DisplayChar(1,50,16);
353     DisplayChar(1,50,17);
354     DisplayChar(1,50,18);
355     DisplayChar(1,50,19);
356     
357     DisplayChar(1,50,24);
358     DisplayChar(1,50,25);
359     DisplayChar(1,50,26);
360     DisplayChar(1,50,27);
361     
362     DisplayChar(1,50,32);
363     DisplayChar(1,50,33);
364     DisplayChar(1,50,34);
365     DisplayChar(1,50,35);
366     
367     DisplayChar(1,50,40);
368     DisplayChar(1,50,41);
369     DisplayChar(1,50,42);
370     DisplayChar(1,50,43);
371     
372     DisplayChar(1,50,48);
373     DisplayChar(1,50,49);
374     DisplayChar(1,50,50);
375     DisplayChar(1,50,51);
376     
377     DisplayChar(1,50,56);
378     DisplayChar(1,50,57);
379     DisplayChar(1,50,58);
380     DisplayChar(1,50,59);
381     
382     DisplayChar(2,50,0);
383     DisplayChar(2,50,1);
384     DisplayChar(2,50,2);
385     DisplayChar(2,50,3);
386     
387     DisplayChar(2,50,8);
388     DisplayChar(2,50,9);
389     DisplayChar(2,50,10);
390     DisplayChar(2,50,11);
391     
392     DisplayChar(2,50,16);
393     DisplayChar(2,50,17);
394     DisplayChar(2,50,18);
395     DisplayChar(2,50,19);
396     
397     DisplayChar(2,50,24);
398     DisplayChar(2,50,25);
399     DisplayChar(2,50,26);
400     DisplayChar(2,50,27);
401     
402     DisplayChar(2,50,32);
403     DisplayChar(2,50,33);
404     DisplayChar(2,50,34);
405     DisplayChar(2,50,35);
406     
407     DisplayChar(2,50,40);
408     DisplayChar(2,50,41);
409     DisplayChar(2,50,42);
410     DisplayChar(2,50,43);
411     
412     DisplayChar(2,50,48);
413     DisplayChar(2,50,49);
414     DisplayChar(2,50,50);
415     DisplayChar(2,50,51);
416     
417     DisplayChar(2,50,56);
418     DisplayChar(2,50,57);
419     DisplayChar(2,50,58);
420     DisplayChar(2,50,59);
421 }

七、一点想法

   LCD12864控制输出时,注意行、列、页之间的 关系。

  使用_nop_()函数可以精确控制延迟时间。

八、附录

 STC单片机指南:点此查看

 实验电路原理图:点击查看

原文地址:https://www.cnblogs.com/liujw2114/p/6142630.html