打印
[牛人杂谈]

新唐M051驱动LCD1602

[复制链接]
1319|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
根据原来用51单片机写LCD160的经验今天用M051的程序重新整理了一遍,并把8位总线和4位总线的的程序整合到一起。从吃完晚饭就坐这,现在都11点多了,整整搞了一个晚上,废话不多说了,抓紧写完睡觉。
1602采用标准的16脚接口,其中:第1脚:VSS为电源地
第2脚:VCC接5V电源正极
第3脚:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高,使用时可以通过一个10K的电位器调整对比度。我用的这款LCD直接接地,对比度是最佳的,省了不少事。
第4脚:RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。
第5脚:RW为读写信号线,高电平(1)时进行读操作,低电平(0)时进行写操作。
第6脚:E(或EN)端为使能端。
第7~14脚:D0~D7为8位双向数据端。
第15脚:背光正极。
第16脚:背光负极。

下图是LCD1602跟M0516的连接图。4总线的D0-D3悬空,D4-D7分别接一个IO的高4位也就是第4-第7位。M0516的这个IO的低4位还可以正常作为其他用途,这样就省了4个IO口。



下面是接8位总线的实物图及显示效果图。


沙发
dongnanxibei|  楼主 | 2017-4-26 21:12 | 只看该作者
下面是接4位总线的实物图及显示效果图。

使用特权

评论回复
板凳
dongnanxibei|  楼主 | 2017-4-26 21:15 | 只看该作者
#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)
    {
    }
}


使用特权

评论回复
地板
wahahaheihei| | 2017-4-26 22:34 | 只看该作者
以前学单片机时候经常用的一个显示屏,学校那个开水点刷卡显示的设备就是这个。

使用特权

评论回复
5
稳稳の幸福| | 2017-4-26 22:40 | 只看该作者
只要学会那个IO的输入输出操作,然后按照时序搞就OK

使用特权

评论回复
6
shen_hao| | 2017-5-17 09:30 | 只看该作者
拿走了,谢谢

使用特权

评论回复
7
稳稳の幸福| | 2017-5-17 10:36 | 只看该作者
把代码和底层分开搞最靠谱

使用特权

评论回复
8
dongnanxibei|  楼主 | 2017-5-18 17:37 | 只看该作者
其实官方应该把常用的那些全部做一套发出来就给力了。

使用特权

评论回复
9
yiy| | 2017-5-18 22:14 | 只看该作者
既可以8BIT,也可以4BIT,很灵活。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

201

主题

3587

帖子

16

粉丝