概述
LCD12864串口模式操作
非转载,仅为个人经验记录。如需转载请注明出处;若有侵权,请管理告知删帖。
- 准备工作
a、硬件及文档
- LCD12864(控制器型号ST7920);
- STM32F103RCT6核心板;
- 杜邦线若干;
- STM32F1标准固件库V3.5;
- ST7920中文、英文版手册;
b、开发环境
- MDK V5.0
c、硬件连接
LCD16284 ----------------> STM32F103RCT6核心板
GND -------------------------> GND
VCC -------------------------> 5V
V0 自己接一个5Ω可调电阻到LCD的Vout
RS ---------------------------> GPIOA_Pin0这几根线参考lcd12864头文件
EN ---------------------------> GPIOA_Pin1
RW ---------------------------> GPIOA_Pin2
- 代码
usr_lcd12864.h
#ifndef _USR_LCD12864_H
#define _USR_LCD12864_H
#include <stdint.h>
// 引脚及对应连接
// LCD -> STM32F103RCT6
// CS -> GPIOA_Pin0
// SCL -> GPIOA_Pin1
// SDA -> GPIOA_Pin2
#define LCD12864_CS_PIN GPIO_Pin_0
#define LCD12864_CS_PORT GPIOA
#define LCD12864_CS_RCC RCC_APB2Periph_GPIOA
#define LCD12864_SCL_PIN GPIO_Pin_1
#define LCD12864_SCL_PORT GPIOA
#define LCD12864_SCL_RCC RCC_APB2Periph_GPIOA
#define LCD12864_SDA_PIN GPIO_Pin_2
#define LCD12864_SDA_PORT GPIOA
#define LCD12864_SDA_RCC RCC_APB2Periph_GPIOA
// 指令预览
#define DISPLAYCLEAR 0x01
#define RETURNHOME 0x02
#define ENTRY_MODE 0x04
#define DISPLAY_CONTROL 0x08
#define CURSOR_DISPLAY 0x10
#define FUNCTION_SET 0x20
#define CGRAM_ADDR 0x40
#define DDRAM_ADDR 0x80
#define STANDBY_MODE 0x01
#define SCROLL_CGRAM_ADDR 0x02
#define REVERSE 0x04
#define EXTENDED_FUNCTION 0x20
#define SCROLL_ADDR 0x40
#define GDRAM_ADDR 0x80
// 引脚操作声明
#define CS_SET() LCD12864_CS_PORT->BSRR=LCD12864_CS_PIN
#define CS_RESET() LCD12864_CS_PORT->BRR=LCD12864_CS_PIN
#define SCL_SET() LCD12864_SCL_PORT->BSRR=LCD12864_SCL_PIN
#define SCL_RESET() LCD12864_SCL_PORT->BRR=LCD12864_SCL_PIN
#define SDA_SET() LCD12864_SDA_PORT->BSRR=LCD12864_SDA_PIN
#define SDA_RESET() LCD12864_SDA_PORT->BRR=LCD12864_SDA_PIN
// 函数声明
void lcd_write_byte( uint8_t dat, uint8_t datflag);
void lcd_port_init( void );
void lcd_device_init(void);
void lcd_init(void);
void lcd_write(uint8_t *dat);
void lcd_display_string(uint8_t *str, uint8_t line, uint8_t colum);
void lcd_display_picture(uint8_t *pic);
void lcd_reverse(uint8_t line_par, uint8_t colum_par, uint8_t width, uint8_t height, uint8_t page_erease, uint8_t reverse);
usr_lcd12864.c
#include "stm32f10x.h"
#include "usr_lcd12864.h"
#include "usr_systick.h"
/* @par1: the value of data or command
* @par2: 0x00 reprenrs command; 0x01 reprenrs data;
*/
void lcd_write_byte( uint8_t dat, uint8_t datflag)
{
uint8_t dat_tmp = 0x00;
uint8_t i_bit = 0;
dat_tmp = ( (datflag&0x01) ? 0xFA : 0xF8 );
for(i_bit=0; i_bit < 8; i_bit++)
{
if( dat_tmp & 0x80 )
SDA_SET();
else
SDA_RESET();
SCL_RESET();
SCL_SET();
SCL_RESET();
dat_tmp = dat_tmp << 1;
}
delay( SYSTICK_PER_SECOND / 2000 );
dat_tmp = dat & 0xF0;
for(i_bit=0; i_bit < 8; i_bit++)
{
SCL_RESET();
if( dat_tmp & 0x80 )
SDA_SET();
else
SDA_RESET();
SCL_RESET();
SCL_SET();
SCL_RESET();
dat_tmp = dat_tmp << 1;
}
dat_tmp = dat << 4;
for(i_bit=0; i_bit < 8; i_bit++)
{
if( dat_tmp & 0x80 )
SDA_SET();
else
SDA_RESET();
SCL_RESET();
SCL_SET();
SCL_RESET();
dat_tmp = dat_tmp << 1;
}
}
/*
* 防止引脚不在同一GPIO口,如在同一GPIO端口,可简化代码
*/
void lcd_port_init( void )
{
GPIO_InitTypeDef lcd_gpio;
lcd_gpio.GPIO_Pin = LCD12864_CS_PIN;
lcd_gpio.GPIO_Mode = GPIO_Mode_Out_PP;
lcd_gpio.GPIO_Speed = GPIO_Speed_10MHz;
RCC_APB2PeriphClockCmd( LCD12864_CS_RCC, ENABLE );
GPIO_Init( LCD12864_CS_PORT, &lcd_gpio );
lcd_gpio.GPIO_Pin = LCD12864_SCL_PIN;
RCC_APB2PeriphClockCmd( LCD12864_SCL_RCC, ENABLE );
GPIO_Init( LCD12864_SCL_PORT, &lcd_gpio );
lcd_gpio.GPIO_Pin = LCD12864_SDA_PIN;
RCC_APB2PeriphClockCmd( LCD12864_SDA_RCC, ENABLE );
GPIO_Init( LCD12864_SDA_PORT, &lcd_gpio );
}
/*
* LCD初始化,设置工作模式、数据宽度等
*/
void lcd_device_init(void)
{
delay(SYSTICK_PER_SECOND / 10);
CS_SET();
lcd_write_byte( 0x0C, 0x00); delay(SYSTICK_PER_SECOND / 100);
lcd_write_byte( 0x01, 0x00); delay(SYSTICK_PER_SECOND / 100);
}
void lcd_init(void)
{
lcd_port_init();
lcd_device_init();
}
/*
* 超过一个字节时,连续写 字符串型 显示数据
*/
void lcd_write(uint8_t *dat)
{
uint8_t *ptr =dat;
while( *ptr )
{
lcd_write_byte( *ptr, 0x01 );
ptr++;
}
}
/*
* @par1: the character string will be displaied.
* @par2: the vertical position of LCD 1-4
* @par3: the horizontal postion of LCD 1-8
*/
void lcd_display_string(uint8_t *str, uint8_t line, uint8_t colum)
{
const uint8_t line_pos[]= {0x80, 0x90, 0x88, 0x98};
lcd_write_byte( line_pos[line - 1] + (colum - 1), 0x00 );
lcd_write( str );
}
void lcd_display_picture(uint8_t *pic)
{
uint8_t pos_i = 0;
uint8_t pos_j = 0;
uint8_t *tmp = pic;
uint8_t pos_x = 0x80;
uint8_t pos_y = 0x80;
uint16_t k=0;
for( pos_i = 0; pos_i < 32; pos_i ++ )
{
lcd_write_byte( pos_y, 0x00 );
lcd_write_byte( pos_x, 0x00 );
for( pos_j = 0; pos_j < 16; pos_j ++ )
{
lcd_write_byte( tmp[k++], 0x01 );
}
pos_y ++;
}
pos_x = 0x88;
pos_y = 0x80;
for( pos_i = 0; pos_i < 32; pos_i ++ )
{
lcd_write_byte( pos_y, 0x00 );
lcd_write_byte( pos_x, 0x00 );
for( pos_j = 0; pos_j < 16; pos_j ++ )
{
lcd_write_byte( tmp[k++], 0x01 );
}
pos_y ++;
}
}
/* @par1: 1~4 big Line
* @par2: 1~8 big colum
* @par3: widthes of each line
* @par4: height of each line
* @par5: clean display page
* @par6: 0x00 nomal; 0xFF reverse
*
*/
void lcd_reverse(uint8_t line_par, uint8_t colum_par, uint8_t width, uint8_t height, uint8_t page_erease, uint8_t reverse)
{
uint8_t pos_x = line_par - 1;
uint8_t pos_y = colum_par - 1;
uint8_t line_i = 0;
uint8_t pot = 0;
extern uint8_t non_tab[];
if(page_erease)
{
lcd_write_byte( 0x36, 0x00);
lcd_display_picture(non_tab);
}
// 确定半屏横坐标基地址
switch( line_par - 1 )
{
case 0: pos_x = 0x80; pos_y = 0x80; break;
case 1: pos_x = 0x80; pos_y = 0x90; break;
case 2: pos_x = 0x88; pos_y = 0x80; break;
case 3: pos_x = 0x88; pos_y = 0x90; break;
}
// 确定在第几列
pos_x = pos_x + colum_par - 1;
for( line_i =0; line_i < height; line_i++ )
{
lcd_write_byte( 0x34, 0x00);
lcd_write_byte( pos_y, 0x00 );
lcd_write_byte( pos_x, 0x00 );
lcd_write_byte( 0x30, 0x00);
for( pot =0; pot < width*2; pot++)
{
lcd_write_byte( reverse, 0x01 );
}
pos_y ++;
}
lcd_write_byte( 0x36, 0x00 );
lcd_write_byte( 0x30, 0x00 );
}
delay函数所在源文件及头文件如下:
usr_systick.h
#ifndef _USR_SYSTICK_H
#define _USR_SYSTICK_H
#include <stdint.h>
//选择延时最小单位为US
#define DELAY_UNIT_US
//定义延时单位所需参数
#if defined DELAY_UNIT_US
#define SYSTICK_PER_SECOND 1000000
#elif defined DELAY_UNIT_10US
#define SYSTICK_PER_SECOND 100000
#elif defined DELAY_UNIT_100US
#define SYSTICK_PER_SECOND 10000
#elif defined DELAY_UNIT_MS
#define SYSTICK_PER_SECOND 1000
#endif
#if !defined (DELAY_UNIT_US) && !defined (DELAY_UNIT_10US) && !defined (DELAY_UNIT_100US) && !defined (DELAY_UNIT_MS)
#error "Please select the delay unit (in systic_delay.h file)"
#endif
void delay_init( void );
void delay( uint32_t nTime );
void TimingDelay_Decrement( void );//在中断函数Systick里调用此
#endif
usr_systick.c
#include "stm32f10x.h"
#include "usr_systick.h"
static uint32_t TimingDly = 0;
void delay_init( void )
{
if( SysTick_Config( SystemCoreClock / SYSTICK_PER_SECOND ) )
while( 1 );
}
void TimingDelay_Decrement( void )
{
if( TimingDly != 0x00 )
TimingDly --;
}
void delay( uint32_t nTime )
{
TimingDly = nTime;
while( TimingDly != 0 );
}
main.c测试
#include "stm32f10x.h"
#include "usr_led.h"
#include "usr_systick.h"
#include "usr_lcd12864.h"
#include "pic.h"
int main(void)
{
uint8_t i = 0;
delay_init();
leds_init();
leds_off();
lcd_init();
uint8_t font[]={0xB0, 0xA1, 0xB0, 0xA1,0xB0, 0xA1,0xB0, 0xA1,0xB0, 0xA1, 0xB0, 0xA1, 0xB0, 0xA1, 0xB0, 0xA1, '