基于stm32f103rct6的LCD1602a 四线驱动
硬件连线
PA0 PA1 PA2 分别连接LCD1602a的 RS RW EN
PA4 PA5 PA6 PA7 分别连接D4 D5 D6 D7
代码部分
本文使用延时策略替代忙等待,因此需要导入 delay 模块
“delay.h”
#ifndef __DELAY_H
#define __DELAY_H
void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
void Delay_s(uint32_t s);
#endif
“delay.c”
#include "stm32f10x.h"
/**
* @brief 微秒级延时
* @param xus 延时时长,范围:0~233015
* @retval 无
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //设置定时器重装值
SysTick->VAL = 0x00; //清空当前计数值
SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器
while(!(SysTick->CTRL & 0x00010000)); //等待计数到0
SysTick->CTRL = 0x00000004; //关闭定时器
}
/**
* @brief 毫秒级延时
* @param xms 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
/**
* @brief 秒级延时
* @param xs 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_s(uint32_t xs)
{
while(xs--)
{
Delay_ms(1000);
}
}
“lcd1602.h”
/*
lcd1602.h
*/
#ifndef __LCD1602_H
#define __LCD1602_H
#include "stm32f10x.h"
#define LCD_DATA_PORT GPIOA
//RS接口
#define LCD_RS_Set() GPIO_SetBits(GPIOA, GPIO_Pin_0)
#define LCD_RS_Clr() GPIO_ResetBits(GPIOA, GPIO_Pin_0)
//RW接口
#define LCD_RW_Set() GPIO_SetBits(GPIOA, GPIO_Pin_1)
#define LCD_RW_Clr() GPIO_ResetBits(GPIOA, GPIO_Pin_1)
//enable接口
#define LCD_EN_Set() GPIO_SetBits(GPIOA, GPIO_Pin_2)
#define LCD_EN_Clr() GPIO_ResetBits(GPIOA, GPIO_Pin_2)
#define u8 unsigned char
void GPIO_Configuration(void);
void LCD1602_Wait_Ready(void);
void LCD1602_Write_Cmd(u8 cmd);
void LCD1602_Write_Dat(u8 dat);
void LCD1602_ClearScreen(void);
void LCD1602_Set_Cursor(u8 x, u8 y);
void LCD1602_Show_Str(u8 x, u8 y, u8 *str);
void LCD1602_Init(void);
void DATAOUT(u8 x);
void LCD1602_Show_num(u8 x,u8 y,u8 num,u8 length);
#endif
“lcd1602.c”
/*
lcd1602.c
*/
#include "lcd1602.h"
#include "Delay.h"
/* 因为使用的都是GPIOA的输出,因此在写入ODR时可能会改变RW RS EN的值,因此单独写了一个函数*/
void DATAOUT(u8 x)
{
if(x&0x80){
GPIOA->ODR |= 0x80;
}else{
GPIOA->ODR &= 0x7f;
}
if(x&0x40){
GPIOA->ODR |= 0x40;
}else{
GPIOA->ODR &= 0xbf;
}
if(x&0x20){
GPIOA->ODR |= 0x20;
}else{
GPIOA->ODR &= 0xdf;
}
if(x&0x10){
GPIOA->ODR |= 0x10;
}else{
GPIOA->ODR &= 0xef;
}
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void LCD1602_Write_Cmd(u8 cmd)
{
// 直接延时实现忙等待
Delay_ms(5);
DATAOUT(cmd); //输出高四位
LCD_RS_Clr(); // 0
LCD_RW_Clr(); // 0
LCD_EN_Set();
LCD_EN_Clr();
DATAOUT(cmd<<4); //将低四位左移后输出
LCD_EN_Set();
LCD_EN_Clr();
}
/* ?1602???????*/
void LCD1602_Write_Dat(u8 dat)
{
// 延时实现忙等待
Delay_ms(5);
LCD_RS_Set(); //1
LCD_RW_Clr(); //0
DATAOUT(dat);
LCD_EN_Set();
LCD_EN_Clr();
DATAOUT(dat<<4);
LCD_EN_Set();
LCD_EN_Clr();
}
void LCD1602_ClearScreen(void)
{ //清屏命令0x01
LCD1602_Write_Cmd(0x01);
}
void LCD1602_Set_Cursor(u8 x, u8 y)
{
u8 address
if (y == 0)
address0x00 + x;
else
address0x40 + x;
LCD1602_Write_Cmd(address|0x80);
}
void LCD1602_Show_Str(u8 x, u8 y, u8 *str)
{
LCD1602_Set_Cursor(x, y);
while(*str != '\0')
{
LCD1602_Write_Dat(*str++);
}
}
void LCD1602_Show_num(u8 x,u8 y,u8 num,u8 length)
{
u8 str[length+1];
for(int i=length-1;i>=0;i--){
str[i]='0'+num%10;
num/=10;
}
LCD1602_Show_Str(x, y, str);
}
void LCD1602_Init(void)
{
LCD1602_Write_Cmd(0x28); //16*2显示,5*7点阵,4位数据口
LCD1602_Write_Cmd(0x0C); //开显示,光标关闭
LCD1602_Write_Cmd(0x06); //文字不动,地址自动+1
LCD1602_Write_Cmd(0x01); //清屏
}
“main.c”
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LCD1602.h"
int main(void)
{
u8 str[] = "LJF001 by HZY";
u8 str1[] = "I love STM32";
GPIO_Configuration();
LCD1602_Init();
LCD1602_ClearScreen();
LCD1602_Show_Str(2, 0, str);
LCD1602_Show_Str(2, 1, str1);
while(1){
}
}