本文為大大維原創,最早於博客園發表,轉載請注明出處!!!
一、實驗目的和要求
掌握點陣式液晶顯示屏的原理和控制方法,掌握點陣字符的顯示方法。
掌握模擬/數字(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單片機指南:點此查看
實驗電路原理圖:點擊查看