|
根據(jù)原來用51單片機(jī)寫LCD160的經(jīng)驗今天用M051的程序重新整理了一遍,并把8位總線和4位總線的的程序整合到一起。從吃完晚飯就坐這,現(xiàn)在都11點多了,整整搞了一個晚上,廢話不多說了,抓緊寫完睡覺。
1602采用標(biāo)準(zhǔn)的16腳接口,其中:第1腳:VSS為電源地
第2腳:VCC接5V電源正極
第3腳:V0為液晶顯示器對比度調(diào)整端,接正電源時對比度最弱,接地電源時對比度最高,使用時可以通過一個10K的電位器調(diào)整對比度。我用的這款LCD直接接地,對比度是最佳的,省了不少事。
第4腳:RS為寄存器選擇,高電平1時選擇數(shù)據(jù)寄存器、低電平0時選擇指令寄存器。
第5腳:RW為讀寫信號線,高電平(1)時進(jìn)行讀操作,低電平(0)時進(jìn)行寫操作。
第6腳:E(或EN)端為使能端。
第7~14腳:D0~D7為8位雙向數(shù)據(jù)端。
第15腳:背光正極。
第16腳:背光負(fù)極。
下圖是LCD1602跟M0516的連接圖。4總線的D0-D3懸空,D4-D7分別接一個IO的高4位也就是第4-第7位。M0516的這個IO的低4位還可以正常作為其他用途,這樣就省了4個IO口。

下面是接8位總線的實物圖及顯示效果圖。

下面是接4位總線的實物圖及顯示效果圖。

#include <M051Series.h>
#define PLLCON_SETTING SYSCLK_PLLCON_50MHz_XTAL
#define PLL_CLOCK 50000000
//#define LCD1602_BUS_NUM 8 //8位數(shù)據(jù)總線,DB0-DB7 按順序接到一個IO口的 0-7位
//4位總線,DB4 - DB7 按順序接到一個IO口的 4-7位,液晶上的DB0-DB3空著,IO口上的0-3位可以正常作為其他用途
#define LCD1602_BUS_NUM 4
#define LCD1602_DATA_PORT P1->DOUT // LCD1602的數(shù)據(jù)總線
#define LCD1602_RS P30 // LCD1602的RS
#define LCD1602_RW P31 // LCD1602的RW
#define LCD1602_E P32 // LCD1602的E控制線
#define LCD1602_Busy P17 // 定義LCD1602的測忙線,應(yīng)該是LCD1602_DB0_DB7的第8位IO口
void SYS_Init(void)
{
/*---------------------------------------------------------------------------------------------------------*/
/* Init System Clock */
/*---------------------------------------------------------------------------------------------------------*/
/* Unlock protected registers */
SYS_UnlockReg();
/* Enable External XTAL (4~24 MHz) */
SYSCLK->PWRCON |= SYSCLK_PWRCON_XTL12M_EN_Msk;
/* Waiting for 12MHz clock ready */
SYS_WaitingForClockReady( SYSCLK_CLKSTATUS_XTL12M_STB_Msk);
/* Switch HCLK clock source to XTAL */
SYSCLK->CLKSEL0 = SYSCLK_CLKSEL0_HCLK_XTAL;
/* Set PLL to power down mode and PLL_STB bit in CLKSTATUS register will be cleared by hardware.*/
SYSCLK->PLLCON|= SYSCLK_PLLCON_PD_Msk;
/* Set PLL frequency */
SYSCLK->PLLCON = PLLCON_SETTING;
/* Waiting for clock ready */
SYS_WaitingForClockReady(SYSCLK_CLKSTATUS_PLL_STB_Msk);
/* Switch HCLK clock source to PLL */
SYSCLK->CLKSEL0 = SYSCLK_CLKSEL0_HCLK_PLL;
/* Enable IP clock */
SYSCLK->APBCLK = SYSCLK_APBCLK_PWM01_EN_Msk;
/* IP clock source */
SYSCLK->CLKSEL1 = SYSCLK_CLKSEL1_PWM01_XTAL;
/* Reset PWMB channel0~channel3 */
SYS->IPRSTC2 = SYS_IPRSTC2_PWM47_RST_Msk;
SYS->IPRSTC2 = 0;
/* Update System Core Clock */
/* User can use SystemCoreClockUpdate() to calculate PllClock, SystemCoreClock and CycylesPerUs automatically. */
//SystemCoreClockUpdate();
PllClock = PLL_CLOCK; // PLL
SystemCoreClock = PLL_CLOCK / 1; // HCLK
CyclesPerUs = PLL_CLOCK / 1000000; // For SYS_SysTickDelay()
/*---------------------------------------------------------------------------------------------------------*/
/* Init I/O Multi-function */
/*---------------------------------------------------------------------------------------------------------*/
/* P2.0 for PWM0 */
//P2.0接LCD1602的背光
SYS->P2_MFP = SYS_MFP_P20_PWM0 ;
/* Lock protected registers */
SYS_LockReg();
}
void PWMA_Init(void)
{
PWMA->PPR = PWM_PPR_CP01(30) ;
PWMA->CSR = PWM_CSR_CSR0(PWM_CSR_DIV16);
//P2.0接LCD1602的背光,可以用PWM進(jìn)行調(diào)光。
/* Enable PWM0 counter. We must set PWM mode before setting CNR, CMR. */
PWMA->PCR = PWM_PCR_CH0EN_Msk | PWM_PCR_CH0MOD_AUTO_RELOAD;
/* PWM0 = 12000000 / 30 / 16 / 200 = 125Hz */
PWMA->CNR0= 200;
PWMA->CMR0= 180;
/* Enable PWM channle 0 Output */
PWMA->POE = PWM_POE_PWM0_Msk;
}
//********************************************************************************************
// 讀LCD忙程序 [底層協(xié)議] // (所有底層協(xié)議都無需關(guān)注)
// LCD1602測忙,若LCD1602處于忙狀態(tài),本函數(shù)將等待至非忙狀態(tài)
//********************************************************************************************/
void LCD1602_TestBusy(void){
LCD1602_DATA_PORT = 0xff; //設(shè)備讀狀態(tài)
SYS_SysTickDelay(5);
LCD1602_RS = 0;
SYS_SysTickDelay(5);
LCD1602_RW = 1;
SYS_SysTickDelay(5);
LCD1602_E = 1;
while(LCD1602_Busy); //等待LCD不忙
LCD1602_E = 0; //
}
//向LCD1602寫入一個指令或者數(shù)據(jù)
//R_S 1是數(shù)據(jù) 0是命令
void LCD1602_WriteByte(uint8_t R_S, uint8_t byte)
{
LCD1602_TestBusy();
LCD1602_RS = R_S;
LCD1602_RW = 0;
#if (LCD1602_BUS_NUM == 8) //8位總線
LCD1602_DATA_PORT = byte;
SYS_SysTickDelay(10);
LCD1602_E = 1;
SYS_SysTickDelay(10);
LCD1602_E = 0;
#elif (LCD1602_BUS_NUM == 4) //4位總線
LCD1602_DATA_PORT &= 0x0f; //高四位清0
LCD1602_DATA_PORT |= (byte&0xf0);//送入高四位數(shù)據(jù)
SYS_SysTickDelay(5);
LCD1602_E = 1;
SYS_SysTickDelay(5);
LCD1602_E = 0;
LCD1602_DATA_PORT &= 0x0f; //高四位清0
LCD1602_DATA_PORT|=(byte<<4&0xf0);//送入低四位數(shù)據(jù)
SYS_SysTickDelay(5);
LCD1602_E = 1;
SYS_SysTickDelay(5);
LCD1602_E = 0;
#endif
}
//********************************************************************************************
// 寫指令程序 //
// 向LCD1602寫命令 本函數(shù)需要1個指令集的入口參數(shù) //
//********************************************************************************************/
void LCD1602_WriteCMD(uint8_t LCD1602_command) {
LCD1602_WriteByte(0x00,LCD1602_command);
}
//********************************************************************************************
// 寫數(shù)據(jù)程序 //
// 向LCD寫數(shù)據(jù) //
//********************************************************************************************/
void LCD1602_WriteData(uint8_t LCD1602_data){
LCD1602_WriteByte(0x01,LCD1602_data);
}
//設(shè)置光標(biāo)位置,line表示第幾行,row表示第幾列
void LCD1602_SetXY(uint8_t line,uint8_t row)
{
uint8_t addr;
if(line>2 || line ==0) line = 1;
if(row>40 || row == 0) row = 1;
row +=0x80;
if(line == 1)
addr = row - 1; //第一行
else if(line == 2)
addr = row - 1 + 0x40; //第二行
LCD1602_WriteCMD(addr);
}
//********************************************************************************************
// 打印字符串程序 // (本函數(shù)調(diào)用指針函數(shù))
//在第x行 第y列 開始顯示字符串
//字符串最長48個
//********************************************************************************************/
void LCD1602_PrintString(uint8_t x,uint8_t y,char *str){
LCD1602_SetXY(x,y);
while(*str != 0){
LCD1602_WriteData(*str++);
}
}
//********************************************************************************************
// 打印單字符程序 //
//在第x行 第y列 顯示字符
//* *******************************************************************************************/
void LCD1602_PrintChar(uint8_t x,uint8_t y,char t){
LCD1602_SetXY(x,y);
LCD1602_WriteData(t);
}
//********************************************************************************************
// LCD初始化 //(使用者可自定義,加 * 號程序行必須保留但可修改)
//********************************************************************************************/
void LCD1602_Init(void){
#if (LCD1602_BUS_NUM == 8) //8位總線
LCD1602_WriteCMD(0x38); // 8總線,顯示2行,每個字符為5*7個像素
#elif (LCD1602_BUS_NUM == 4) //4位總線
LCD1602_WriteCMD(0x28); // 4總線,顯示2行,每個字符為5*7個像素
//需要設(shè)置兩次
LCD1602_WriteCMD(0x28); // 4總線,顯示2行,每個字符為5*7個像素
#endif
LCD1602_WriteCMD(0x01); // 顯示清屏
LCD1602_WriteCMD(0x02); // 數(shù)據(jù)指針指向第1行第1個字符位置
LCD1602_WriteCMD(0x06); // 顯示光標(biāo)移動設(shè)置:文字不動,光標(biāo)右移
LCD1602_WriteCMD(0x0c); // 顯示開及光標(biāo)設(shè)置:顯示開,光標(biāo)開,閃爍開
}
int main(void)
{
SYS_Init();
PWMA_Init();
LCD1602_Init();
LCD1602_PrintString(1,3,"QQ:48469646");
LCD1602_PrintString(2,1,"BUS:4");
LCD1602_PrintChar(2,7,'O');
LCD1602_PrintChar(2,8,'K');
LCD1602_PrintChar(2,9,33); //嘆號
while(1)
{
}
}
|
|