#include <M051Series.h>
#define PLLCON_SETTING SYSCLK_PLLCON_50MHz_XTAL
#define PLL_CLOCK 50000000
//#define LCD1602_BUS_NUM 8 //8位数据总线,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的数据总线
#define LCD1602_RS P30 // LCD1602的RS
#define LCD1602_RW P31 // LCD1602的RW
#define LCD1602_E P32 // LCD1602的E控制线
#define LCD1602_Busy P17 // 定义LCD1602的测忙线,应该是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进行调光。
/* 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忙程序 [底层协议] // (所有底层协议都无需关注)
// LCD1602测忙,若LCD1602处于忙状态,本函数将等待至非忙状态
//********************************************************************************************/
void LCD1602_TestBusy(void){
LCD1602_DATA_PORT = 0xff; //设备读状态
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写入一个指令或者数据
//R_S 1是数据 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);//送入高四位数据
SYS_SysTickDelay(5);
LCD1602_E = 1;
SYS_SysTickDelay(5);
LCD1602_E = 0;
LCD1602_DATA_PORT &= 0x0f; //高四位清0
LCD1602_DATA_PORT|=(byte<<4&0xf0);//送入低四位数据
SYS_SysTickDelay(5);
LCD1602_E = 1;
SYS_SysTickDelay(5);
LCD1602_E = 0;
#endif
}
//********************************************************************************************
// 写指令程序 //
// 向LCD1602写命令 本函数需要1个指令集的入口参数 //
//********************************************************************************************/
void LCD1602_WriteCMD(uint8_t LCD1602_command) {
LCD1602_WriteByte(0x00,LCD1602_command);
}
//********************************************************************************************
// 写数据程序 //
// 向LCD写数据 //
//********************************************************************************************/
void LCD1602_WriteData(uint8_t LCD1602_data){
LCD1602_WriteByte(0x01,LCD1602_data);
}
//设置光标位置,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);
}
//********************************************************************************************
// 打印字符串程序 // (本函数调用指针函数)
//在第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个像素
//需要设置两次
LCD1602_WriteCMD(0x28); // 4总线,显示2行,每个字符为5*7个像素
#endif
LCD1602_WriteCMD(0x01); // 显示清屏
LCD1602_WriteCMD(0x02); // 数据指针指向第1行第1个字符位置
LCD1602_WriteCMD(0x06); // 显示光标移动设置:文字不动,光标右移
LCD1602_WriteCMD(0x0c); // 显示开及光标设置:显示开,光标开,闪烁开
}
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)
{
}
}
|