NRF51822——LCD128X64驱动

前言:

为了方便查看博客,特意申请了一个公众号,附上二维码,有兴趣的朋友可以关注,和我一起讨论学习,一起享受技术,一起成长。

在这里插入图片描述


1.概述

128X64的LCD可以显示 128 列64 行点阵单色图片,或显示 8 个/行4 行 1616 点阵的汉字,或显示 16 个/行8 行 8*8 点阵的英文、数字、符号。驱动IC为 ST7565R。在 LCD 上排列着 128×64 点阵,128 个列信号与驱动 IC 相连,64 个行信号也与驱动 IC 相连,IC 邦定在 LCD 玻璃上( COG工艺)。

2.硬件设计

2.1 连接原理图

这里写图片描述

硬件连接:

这里写图片描述

2.2 模块的引脚功能

模块通过 SPI 进行通信,需要的引脚如下图:

这里写图片描述

2.3 点阵与 DD RAM 地址的对应

**页定义:**PAGE,与平时所讲的“页”并不是一个意思,在此表示 8 个行就是一个“页”,一个 128*32 点阵的屏分为 8 个“页”,从第 0“页”到第 7“页”。

这里写图片描述

3.软件实现

这里写图片描述

3.1 模拟SPI时序
//头文件
#ifndef _SPI_H_
#define	_SPI_H_

#include "nrf51.h"
#include "nrf_gpio.h"

#define SPI_CLK       2
#define SPI_CLK_LOW 		nrf_gpio_pin_clear(SPI_CLK)
#define SPI_CLK_HIGH 		nrf_gpio_pin_set(SPI_CLK)

#define SPI_MOSI  	   1
#define SPI_MOSI_LOW 		nrf_gpio_pin_clear(SPI_MOSI )
#define SPI_MOSI_HIGH		nrf_gpio_pin_set(SPI_MOSI)

#define SPI_MISO  	   0
#define SPI_MISO_LOW 		nrf_gpio_pin_clear(SPI_MISO )
#define SPI_MISO_HIGH		nrf_gpio_pin_set(SPI_MISO)
#define SPI_MISO_READ		nrf_gpio_pin_read(SPI_MISO)

void Spi_Gpio_Init(void);
void Spi_Write_Byte(uint8_t dat);
uint8_t Spi_Read_Byte(void);

#endif
//源程序
#include "spi.h"
#include "nrf_delay.h"
#include "nrf_gpio.h"
#include <stdint.h>
#include "lcd128x64.h"

//定义SPI四钟方式的0和3
#define _CPOL	0
#define	_CPHA	0

void Spi_Gpio_Init(void)
{
	nrf_gpio_cfg_output(SPI_CLK);
	nrf_gpio_cfg_output(SPI_MOSI);
	nrf_gpio_cfg_input(SPI_MISO,NRF_GPIO_PIN_NOPULL);
#if _CPOL==0
	SPI_CLK_LOW;
#else
	SPI_CLK_HIGH;
#endif
}

//模式0:CPOL=0;CPAH=0
//模拟SPI写数据
#if _CPOL==0&&_CPHA==0  
void Spi_Write_Byte(uint8_t dat)
{
    uint8_t len;
  
    for(len=0;len<8;len++)
    {
        SPI_CLK_LOW;//时钟上升沿采样传输数据
				//nrf_delay_ms(1);
        if(dat&0x80)	//发送数据
				{
					SPI_MOSI_HIGH;
				} 
        else
        {
					SPI_MOSI_LOW;
				}
        SPI_CLK_HIGH;
			//	nrf_delay_ms(1);
        dat <<= 1;
    }
}

//模拟SPI读数据
uint8_t Spi_Read_Byte(void)
{
	uint8_t cnt;
	uint8_t dat=0;

	for(cnt=0;cnt<8;cnt++)	
	{
		SPI_CLK_LOW;	//下降沿后读取数据
		nrf_delay_ms(1);
		dat <<= 1;	//最高位已经在数据线上了
		if(SPI_MISO_READ)	//
		{
			dat |= 0x01;
		}
		else
		{
			dat &= 0xfe;
		}
		//dat <<= 1;注:此处最高位被移除了
		SPI_CLK_HIGH;
		nrf_delay_ms(1);
	}
	
	return dat;
}
#endif


//模式3:CPOL=1;CPAH=1
//模拟SPI写数据
#if _CPOL==1&&_CPHA==1            //MODE  1  1
void Spi_Write_Byte(uint8_t dat)
{
    uint8_t len;
	
	SPI_CLK_HIGH;
    for(len=0;len<8;len++)
    {
        SPI_CLK_LOW;//时钟上升沿输出数据
				//nrf_delay_ms(1);
        if(dat&0x80)	//发送数据
				{
					SPI_MOSI_HIGH;
				} 
        else
        {
					SPI_MOSI_LOW;
				}
        SPI_CLK_HIGH;
			//	nrf_delay_ms(1);
        dat <<= 1;
    }
}

//模拟SPI读数据
uint8_t Spi_Read_Byte(void)
{
	uint8_t cnt;
	uint8_t dat=0;
	
	SPI_CLK_LOW;
	for(cnt=0;cnt<8;cnt++)	
	{
		SPI_CLK_LOW;
		nrf_delay_ms(1);
		dat <<= 1;
		if(SPI_MISO_READ)	
		{
			dat |= 0x01;
		}
		else
		{
			dat &= 0xfe;
		}
		SPI_CLK_HIGH;
		nrf_delay_ms(1);
	}
	SPI_CLK_HIGH;
	
	return dat;
}
#endif

模拟SPI的介绍请移步SPI专题(一)——基础知识

3.2 LCD驱动
//头文件
#ifndef __LCD128X64__H__
#define __LCD128X64__H__

#include "nrf51.h"
#include "nrf_gpio.h"

#define Max_Column 128
#define Max_Row		64 
#define SIZE 16

#define LCD_CMD  0	//写命令
#define LCD_DATA 1	//写数据

#define LED_LIGHT1 	28

#define LCD_CS         3
#define LCD_CS_LOW			nrf_gpio_pin_clear(LCD_CS)
#define LCD_CS_HIGH 		nrf_gpio_pin_set(LCD_CS)

#define LCD_RST       4
#define LCD_RST_LOW 		nrf_gpio_pin_clear(LCD_RST)
#define LCD_RST_HIGH 		nrf_gpio_pin_set(LCD_RST)

#define LCD_A0         5
#define LCD_A0_LOW 			nrf_gpio_pin_clear(LCD_A0)
#define LCD_A0_HIGH 		nrf_gpio_pin_set(LCD_A0)


typedef enum
{
	FONT_5X8 = 1,
	FONT_8X16,
	FONT_16X16,
	FONT_128X64,
	SHOW_POINT,
	SHOW_LINE
}Typeface;

void GPIO_LCD_Init(void);
void LCD_Write_Byte(uint8_t dat,uint8_t cmd);

void LCD_Init(void);
void LCD_Set_Pos(uint8_t page,uint8_t column);
void LCD_Display_Clear(void);

void LCD_Draw_Point(uint8_t page,uint8_t column);
void LCD_Draw_Line_Y(uint8_t page,uint8_t column);
void LCD_All_Screen(void);
void Lcd_Display_OneChar(uint8_t page,uint8_t column,uint8_t str);
void Lcd_Display_String(uint8_t page,uint8_t column,uint8_t *str);
uint32_t Lcd_Pow(uint8_t m,uint8_t n);
void Lcd_Display_Num(uint8_t page,uint8_t column,uint32_t num,uint8_t len,uint8_t size_num);


void Display_128x64(uint8_t *dp);
void Display_Graphic_5x8(uint8_t page,uint8_t column,uint8_t *dp);
void Display_Graphic_8x16(uint8_t page,uint8_t column,uint8_t *dp);
void Display_Graphic_16x16(uint8_t page,uint8_t column,uint8_t *dp);

void DisplayFont(uint8_t page, uint8_t column, uint8_t No, uint8_t typeface);
void display_string_8x16(uint8_t page,uint8_t column,uint8_t *text);

void Lcd_Light(void);

void OLED_Init(void);

void LCD_Draw_Line_X(uint8_t page,uint8_t column);

#endif
//源文件,相关GPIO初始化
void GPIO_LCD_Init(void)
{
	nrf_gpio_cfg_output(LCD_CS);
	nrf_gpio_cfg_output(LCD_RST);
	nrf_gpio_cfg_output(LCD_A0);
	
	LCD_CS_HIGH;
}

MCU向LCD的写入数据:

这里写图片描述

//LCD写数据
void LCD_Write_Byte(uint8_t dat,uint8_t cmd)
{
   // uint8_t len;
		LCD_CS_LOW;
	
    if(cmd)
        LCD_A0_HIGH;
    else
        LCD_A0_LOW;
  
	Spi_Write_Byte(dat);
	LCD_CS_HIGH;
    LCD_A0_HIGH;
}
//初始化
void LCD_Init(void)
{
	LCD_RST_HIGH;
	nrf_delay_ms(20);
	LCD_RST_LOW;
	nrf_delay_ms(20);
	LCD_RST_HIGH;
	
	LCD_Write_Byte(0xe2,LCD_CMD);	//软复位
	nrf_delay_ms(20);
	
	LCD_Write_Byte(0xae,LCD_CMD);//显示关闭
	LCD_Write_Byte(0x2c,LCD_CMD);// open VB circuit
	nrf_delay_ms(20);
	LCD_Write_Byte(0x2e,LCD_CMD);// open VR circuit
	nrf_delay_ms(20);
	LCD_Write_Byte(0x2f,LCD_CMD);//voltage follower ON  regulator ON  booster ON
	nrf_delay_ms(20);
	LCD_Write_Byte(0x22,LCD_CMD);
	LCD_Write_Byte(0x81,LCD_CMD);
	LCD_Write_Byte(0x3f,LCD_CMD);
	LCD_Write_Byte(0xa2,LCD_CMD);//
    
	LCD_Write_Byte(0xa0,LCD_CMD);
	LCD_Write_Byte(0xc8,LCD_CMD);//com64 --> com1
	
	LCD_Write_Byte(0x10,LCD_CMD);//Set Column Address 4 higher bits = 0
	LCD_Write_Byte(0x00,LCD_CMD);//Set Column Address 4 lower bits = 1 , from IC SEG1 -> SEG128
	LCD_Write_Byte(0xb0,LCD_CMD);//Set Page Address = 0
	LCD_Write_Byte(0xa6,LCD_CMD);//Normal Display (not reverse dispplay)
	LCD_Write_Byte(0xaf,LCD_CMD);//Display ON
	/*
	LCD_Write_Byte(0xa0,LCD_CMD);  //列扫描顺序:从左到右
	LCD_Write_Byte(0xc0,LCD_CMD);  //行扫描顺序:C8:从下到上,c0:从上到下
	LCD_Write_Byte(0xa2,LCD_CMD);	 //设置偏压比1/9
	LCD_Write_Byte(0x2f,LCD_CMD);	//控制电源
	LCD_Write_Byte(0x25,LCD_CMD);	//粗调对比度
	LCD_Write_Byte(0x81,LCD_CMD);  //微调对比度,进入微调对比度命令
	LCD_Write_Byte(0x10,LCD_CMD);  //设置电压的参数RR值
	LCD_Write_Byte(0x40,LCD_CMD);  //起始行:第一行开始
	LCD_Write_Byte(0xaf,LCD_CMD);  //开显示*/
	
	LCD_Display_Clear();
	LCD_Set_Pos(0,0);
}
//坐标设置
void LCD_Set_Pos(uint8_t page,uint8_t column)
{
	LCD_Write_Byte(0xb0 + page,LCD_CMD);	//64行分成8个页
	LCD_Write_Byte(((column >> 4) & 0x0f) | 0x10,LCD_CMD);	//列地址高四位
	LCD_Write_Byte((column & 0x0f) | 0x01,LCD_CMD);		//设置列地址的低四位
}
//清屏
/清屏
void LCD_Display_Clear(void)
{
	uint8_t page,j;
	
	for(page=0;page<8;page++)
	{
		LCD_Write_Byte(0xb0+page,LCD_CMD);	//设置显示页地址,即横坐标
		LCD_Write_Byte(0X00,LCD_CMD);	//列地址的低 4 位
		LCD_Write_Byte(0X10,LCD_CMD); 	//列地址的高 4 位
		for(j=0;j<128;j++)
		{
			LCD_Write_Byte(0X00,LCD_DATA);//写入1则显示,写入0则清屏
		}
	}
}
//显示相关实现
/*显示128x64点阵图像*/
void Display_128x64(uint8_t *dp)
{
	uint8_t i,j;
	
	for(j=0;j<8;j++)
	{
		LCD_Set_Pos(j+1,1);
		for (i=0;i<128;i++)
		{	
		  LCD_Write_Byte(*dp,LCD_DATA);	 	/*写数据到LCD,每写完一个8位的数据后列地址自动加1*/
		  dp++;
		}
	}
}

//显示一个点
void LCD_Draw_Point(uint8_t page,uint8_t column)
{
	LCD_Set_Pos(page, column);
	LCD_Write_Byte(0x01,LCD_DATA);
}

//划线
void LCD_Draw_Line_Y(uint8_t page,uint8_t column)
{
	uint8_t i,j;
	
	for(i=page;i<8;i++)
	{
		LCD_Write_Byte(0xb0+i,LCD_CMD);	//设置显示页地址,即横坐标
		for(j=0;j<0x08;j++)
		{
			LCD_Write_Byte(0x00+j,LCD_CMD);	//只加其中低或者高,相当于连续显示竖线
			LCD_Write_Byte(0X10+j,LCD_CMD); 	//横纵坐标都同时递增,相当于竖线平移
			LCD_Write_Byte(0Xff,LCD_DATA);//写入1则显示,写入0则清屏
		}
	}
}

//可构造斑马线
void LCD_Draw_Line_X(uint8_t page,uint8_t column)
{
	uint8_t i,j;
	
	LCD_Set_Pos(page, column);
	for(j=0;j<8;j++)
	{
		LCD_Write_Byte(0xb0+j,LCD_CMD);
		LCD_Write_Byte(0X00,LCD_CMD);	//列地址的低 4 位
		LCD_Write_Byte(0X10,LCD_CMD); 	//列地址的高 4 位
		for(i=0;i<128;i++)
		{
			//LCD_Write_Byte(0x0f,LCD_DATA);
			LCD_Write_Byte(0x01,LCD_DATA);
		}
	}
}

/显示单独一个字符
void Lcd_Display_OneChar(uint8_t page,uint8_t column,uint8_t str)
{
	uint8_t i=0,ret=0;
	//ret = str -32;
	ret = str - ' ';//得到偏移后的值,对ASCLL码进行一个减法.即在二维数组里找它的位置  
	if(column>Max_Column-1)
	{
		column = 0;
		page = page + 2;//针对16号的字符
	}
	if(SIZE == 16 )
	{
		LCD_Set_Pos(page,column);
		//16的字体分成两部分写入
		for(i=0;i<8;i++)
		{
			LCD_Write_Byte(F8X16[ret*16+i],LCD_DATA);
		}
		LCD_Set_Pos(page+1,column);//页地址增加1
		for(i=0;i<8;i++)
		{
				LCD_Write_Byte(F8X16[ret*16+i+8],LCD_DATA);
		}
	}
	else{
		LCD_Set_Pos(page,column+1);
		for(i=0;i<6;i++)
			LCD_Write_Byte(F6x8[ret][i],LCD_DATA);
	}
}
//字符串显示
void Lcd_Display_String(uint8_t page,uint8_t column,uint8_t *str)
{
	uint8_t i=0;
	
	while(str[i]!='\0')
	{
		Lcd_Display_OneChar(page,column,str[i]);
		column += 8;
		if(column>120)
		{
			column = 0;
			page += 2;
		}
		i++;
	}
}

//计算m的n次方
uint32_t Lcd_Pow(uint8_t m,uint8_t n)
{
    uint32_t ret = 1;
    
    while(n--)
		{
			ret *= m;
		}
      
    return ret;
}

//显示数字
//*num:显示的数字
void Lcd_Display_Num(uint8_t page,uint8_t column,uint32_t num,uint8_t len,uint8_t size_num)
{
    uint8_t t,temp;
    uint8_t flag = 0;

    for(t=0;t<len;t++)
    {
        temp = (num / Lcd_Pow(10,len-t-1)) % 10;//把显示的数字一位一位取出来
        if(((flag==0) && t) < (len-1))
        {
            if(temp == 0)
            {
                Lcd_Display_OneChar(page,column + (size_num/2) * t,'0');
                continue;//temp=0时,结束本次循环,进入下次循环,但不跳出循环
            }
            else
            {
							flag = 1;
            }
               
        }
        Lcd_Display_OneChar(page,column + (size_num/2) * t,temp + '0');
    }
}

**注:**程序中涉及的字库可通过取自摸软件得到。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值