感謝北京化工大學何賓老師的課程指導,今天我們分享一個利用STC15W4K32S4單片機實現的ADC應用,我們通過ADC轉換實現在LCD1602上顯示學號,並能夠通過外部中斷0和外部中斷1分別實現學號左移和右移的功能。
以下是項目代碼:
1、lcd1602.h
// 條件編譯指令,如果未定義_1602_則定義_1602
#ifndef _1602_
#define _1602_
// 引入頭文件
#include "reg51.h"
#include "intrins.h"
// 定義LCD引腳及寄存器地址
sbit LCD1602_RS = P2^5; // 定義LCD1602_RS爲P2.5引腳,RS=0表示傳輸的是控制指令,RS=1表示傳輸的是數據
sbit LCD1602_RW = P2^6; // 定義LCD1602_RW爲P2.6引腳,R/W=0表示讀操作,R/W=1表示寫操作
sbit LCD1602_E = P2^7; // 定義LCD1602_E 爲P2.7引腳,E=1,單片機將數據放入數據線,一段時間後拉低,數據繼續維持一段時間,即寫入LCD中
sfr LCD1602_DB = 0x80; // 定義LCD1602_DB爲P0端口
sfr P0M1 = 0x93; // 定義P0端口P0M1寄存器地址0x93
sfr P0M0 = 0x94; // 定義P0端口P0M0寄存器地址0x94
sfr P2M1 = 0x95; // 定義P2端口P2M1寄存器地址0x95
sfr P2M0 = 0x96; // 定義P2端口P2M0寄存器地址0x96
// 申明函數
void lcdwait(); // 等待LCD空閒函數
void lcdwritecmd(unsigned char cmd); // 寫LCD命令函數
void lcdwritedata(unsigned char dat); // 寫LCD數據函數
void lcdinit(); // 初始化LCD函數
void lcdsetcursor(unsigned char x, unsigned char y); // 設定LCD光標位置函數
void lcdshowstr(unsigned char x, unsigned char y, unsigned char *str); // 打印字符串函數
// 條件預編譯指令結束
#endif
2、led1602.c
// 引入頭文件
#include "led1602.h"
// 實現函數
/**
* 函數名:lcdwait()
* 參數 :無
* 功能 :等待LCD空閒
*/
void lcdwait() {
LCD1602_DB = 0xFF; // 讀取前,置P0端口爲FF,引腳相當於懸空
_nop_(); // 空操作指令,延遲
_nop_();
_nop_();
_nop_();
LCD1602_RS = 0; // 將RS信號拉低
LCD1602_RW = 1; // 將RW信號拉高
LCD1602_E = 1; // 將E 信號拉高
while(LCD1602_DB & 0x80); // 等待標誌BF爲低,即LCD空閒
LCD1602_E = 0; // 將E 信號拉低
}
/**
* 函數名:lcdwritecmd()
* 參數 :cmd 控制指令碼
* 功能 :寫LCD命令
*/
void lcdwritecmd(unsigned char cmd) {
lcdwait(); // 等待LCD空閒
_nop_();
_nop_();
_nop_();
_nop_();
LCD1602_RS = 0;
LCD1602_RW = 0;
LCD1602_DB = cmd; // 將控制指令碼放到P0端口
LCD1602_E = 1;
_nop_();
_nop_();
_nop_();
_nop_();
LCD1602_E = 0;
}
/**
* 函數名:lcdwritecmd()
* 參數 :dat 數據碼
* 功能 :寫LCD數據
*/
void lcdwritedata(unsigned char dat) {
lcdwait(); // 等待LCD空閒
_nop_();
_nop_();
_nop_();
_nop_();
LCD1602_RS = 1;
LCD1602_RW = 0;
LCD1602_DB = dat; // 將數據碼放到P0端口
LCD1602_E = 1;
_nop_();
_nop_();
_nop_();
_nop_();
LCD1602_E = 0;
}
/**
* 函數名:lcdinit()
* 參數 :無
* 功能 :初始化LCD
*/
void lcdinit() {
lcdwritecmd(0x38); // 發指令0x38,2行模式,5x8點陣,8位寬度
lcdwritecmd(0x0c); // 發指令0x0c,打開顯示,關閉光標
lcdwritecmd(0x06); // 發指令0x06,文字不移動,地址自動加1
lcdwritecmd(0x01); // 發指令0x01,清屏
}
/**
* 函數名:lcdsetcursor()
* 參數 :x 在LCD上的列數
* y 在LCD上的行數
* 功能 :設定LCD光標位置
*/
void lcdsetcursor(unsigned char x, unsigned char y) {
unsigned char address; // 存儲器地址
if(y==0) // 在第一行
address = 0x00 + x;
else // 在第二行
address = 0x40 + x;
lcdwritecmd(address | 0x80); // 寫存儲器地址指令
}
/**
* 函數名:lcdshowstr()
* 參數 :x 在LCD上的列數
* y 在LCD上的行數
* str 需要打印的字符串
* 功能 :打印字符串
*/
void lcdshowstr(unsigned char x, unsigned char y, unsigned char *str) {
lcdsetcursor(x, y); // 設置光標位置
while((*str) != '\0') { // 字符串未到結尾
lcdwritedata(*str); // 傳送字符數據
str++; // 字符串地址自增
}
}
3、main.c
// 引入頭文件
#include "reg51.h"
#include "stdio.h"
#include "led1602.h"
#define ADC_POWER 0x80 // 定義ADC_POWER 的值爲0x80
#define ADC_FLAG 0x10 // 定義ADC_FLAG 的值爲0x10
#define ADC_START 0x08 // 定義ADC_START 的值爲0x08
#define ADC_SPEEDLL 0x00 // 定義ADC_SPEEDLL的值爲0x00
#define ADC_SPEEDL 0x20 // 定義ADC_SPEEDL 的值爲0x20
#define ADC_SPEEDH 0x40 // 定義ADC_SPEEDH 的值爲0x40
#define ADC_SPEEDHH 0x60 // 定義ADC_SPEEDHH的值爲0x60
sfr AUXR = 0x8E; // 申明AXUR寄存器的地址爲0x8E
sfr ADC_CONTR = 0xBC; // 申明ADC_CONTR控制寄存器的地址爲0xBC
sfr ADC_RES = 0xBD; // 申明ADC_RES結果寄存器的地址爲0xBD
sfr ADC_RESL = 0xBE; // 申明ADC_RESL結果寄存器的地址爲0xBE
sfr P1ASF = 0x9D; // 申明P1ASF模擬功能控制寄存器的地址爲0x9D
// 在外部數據區定義變量,用於存儲學號
xdata long num1 _at_ 0x100; // 定義長整形變量num1
xdata float num2 _at_ 0x120; // 定義浮點數變量num2
unsigned char ch = 4;
bit flag = 1; // ADC轉換完成標識
unsigned char tstr[50]; // 數據存儲緩衝器
/**
* 函數名:delay
* 參數 :n 延遲時間長度,單位毫秒
* 功能 :延時指定的毫秒時間
*/
void delay(unsigned int n) {
unsigned int i, j;
for(i = n; i > 0; i--) {
for(j = 114; j > 0; j--);
}
}
/**
* 函數名:adc_int
* 參數 :無
* 功能 :ADC中斷響應函數
*/
void adc_int() interrupt 5 {
unsigned char i = 0;
ADC_CONTR &= !ADC_FLAG; // 將ADC_FLAG標誌清零
num1 = 2016014446;
num2 = 2016014446;
sprintf(tstr + 10, "%lld", num1); // 將數據傳送至緩衝區
flag = 1; // ADC轉換完成
ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START | ch; // 啓動ADC
}
/**
* 函數名:move_left
* 參數 :無
* 功能 :外部中斷0中斷響應函數,實現學號在LCD上左移
*/
void move_left() interrupt 0 {
unsigned char i;
for(i = 0; i < 11; i++){
lcdwritecmd(0x01); // 清屏
lcdwait(); // 等待LCD空閒
lcdshowstr(0, 0, tstr+10+i); // 右移數組地址,寫字符串
lcdwait();
delay(3000); // 延時等待
}
}
/**
* 函數名:move_right
* 參數 :無
* 功能 :外部中斷1中斷響應函數,實現學號在LCD上右移
*/
void move_right() interrupt 2 {
unsigned char i;
for(i = 6; i < 17; i++){
lcdwritecmd(0x01); // 清屏
lcdwait(); // 等待LCD空閒
lcdshowstr(i, 0, tstr+10); // 右移光標位置,寫字符串
lcdwait();
delay(3000); // 延時等待
}
}
/**
* 函數名:main
* 參數 :無
* 功能 :主函數,在LCD上打印學號,響應中斷
*/
void main() {
unsigned int i, k;
P0M0 = 0; // 通過P0M0和P0M1寄存器將P0口定義爲準雙向(雙向IO),弱上拉(上拉電阻很大,提供的驅動電流很小,叫弱上拉)
P0M1 = 0;
P2M0 = 0; // 通過P2M0和P2M1寄存器將P2口定義爲準雙向,弱上拉
P2M1 = 0;
P1ASF = 0xFF; // 將P1端口用於ADC輸入
ADC_RES = 0; // 將ADC_RES寄存器清零
ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START | ch; // 配置ADC_CONTR寄存器
for(i = 0; i < 10000; i++);
IE = 0xA0; // 允許ADC中斷
lcdwait(); // 等待LCD空閒
lcdinit(); // 初始化LCD
IT0 = 1; // 開啓外部中斷0和外部中斷1
EX0 = 1;
IT1 = 1;
EX1 = 1;
EA = 1;
while(1) {
if(flag == 1) {
flag = 0;
for(k = 0; k < 16; k++) {// 循環打印學號
lcdwritecmd(0x01);
lcdwait();
lcdshowstr(k, 0, tstr+10);
if(k > 6)
lcdshowstr(0, 0, tstr+26-k);
lcdwait();
delay(500);
}
}
}
}
有關講解的視頻歡迎關注我們的公衆號:落餅楓林,查看歷史推送:STC15W4K32S4單片機ADC應用實現。
想要學習更多單片機的知識也歡迎參加何老師在愛課程網站上的單片機原理及應用的課程:https://www.icourse163.org/learn/BUCT-1205804839#/learn/announce