使用stm32f103驱动lcd1602

简介: 使用stm32f103驱动lcd1602

1. 项目需求

  • 使用上位机发送ASCII字符,在LCD1602上能够实时显示

2. 使用到的软件和硬件

  • 野火指南者开发板

image.png

  • - LCD1602液晶屏

218eed299b25428cadb1a49d8e9ab213.png


  • 杜邦线
  • DAP仿真器
  • KEIL5

3. 连线说明


234f95c80053494d85c30e8dd48629ce.png

4. 代码

  1. LCD驱动代码
    头文件:
#ifndef __LCD_H
#define __LCD_H
#include "stm32f10x.h"
typedef unsigned char uint_8;
typedef unsigned int  uint_16;
// 控制端引脚
#define CON_GPIO           GPIOC
#define LCD_CON_RCC_FUNC   RCC_APB2PeriphClockCmd
#define CON_GPIO_CLK       RCC_APB2Periph_GPIOC
#define CON_RS_PIN         GPIO_Pin_8
#define CON_RW_PIN         GPIO_Pin_9
#define CON_E_PIN          GPIO_Pin_10
// 数据传输端引脚
#define DATA_GPIO          GPIOB
#define LCD_DATA_RCC_FUNC  RCC_APB2PeriphClockCmd
#define DATA_GPIO_CLK      RCC_APB2Periph_GPIOB
#define DATA0_PIN          GPIO_Pin_8
#define DATA1_PIN          GPIO_Pin_9
#define DATA2_PIN          GPIO_Pin_10
#define DATA3_PIN          GPIO_Pin_11
#define DATA4_PIN          GPIO_Pin_12
#define DATA5_PIN          GPIO_Pin_13
#define DATA6_PIN          GPIO_Pin_14
#define DATA7_PIN          GPIO_Pin_15
// 常用指令
#define CLEAR                0x01   // 清屏
#define CURSOR_RESET         0x10   // 光标归位
#define AFTER_CL             0x04   // 写入数据后,光标左移,显示屏不移动
#define AFTER_CL_SR          0x05   // 写入数据后,光标左移,显示屏整体向右移动
#define AFTER_CR             0x06   // 写入数据后,光标右移,显示屏不移动
#define AFTER_CR_SR          0x07   // 写入数据后,光标右移,显示屏整体向右移动
#define CLOSE_CURSOR         0x0C   // 无光标
#define SHOW_CURSOR_TWINKLE  0x0f   // 光标闪烁
#define SHOW_CURSOR          0x0e   // 光标不闪烁
#define CURSOR_LEFT          0x10   // 光标左移一格
#define CURSOR_RIGHT         0x14   // 光标右移一格
#define SCREEN_LEFT          0x18   // 显示屏上字符全部左移一格,光标不动
#define SCREEN_RIGHT         0x1C   // 显示屏上所有字符右移一格,光标不动
#define SHOW_ONE_5X7         0x30   // 显示一行,5X7点阵 (默认数据总线为8位)
#define SHOW_ONE_5X10        0x34   // 显示一行,5X10
#define SHOW_TWO_5X7         0x38   // 显示两行,5X7
#define SHOW_TWO_5X10        0x3C   // 显示两行,5X10
void LCD_Init(void);
void LCD_WriteData(uint_8 data);
void LCD_WriteCon(uint_8 data);
#endif

源文件

#include "lcd.h"
static void LCD_Desplay(uint_16 x)
{
  while(x--);
}
static void GPIO_InitConifg()
{
  GPIO_InitTypeDef GPIO_Structure;
  // 开启时钟
  LCD_CON_RCC_FUNC(CON_GPIO_CLK, ENABLE);
  LCD_DATA_RCC_FUNC(DATA_GPIO_CLK, ENABLE);
  // 控制端
  GPIO_Structure.GPIO_Pin = CON_RS_PIN;
  GPIO_Structure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
  GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(CON_GPIO, &GPIO_Structure);
  GPIO_Structure.GPIO_Pin = CON_RW_PIN;
  GPIO_Init(CON_GPIO, &GPIO_Structure);
  GPIO_Structure.GPIO_Pin = CON_E_PIN;
  GPIO_Init(CON_GPIO, &GPIO_Structure);
  // 输出端
  GPIO_Structure.GPIO_Pin = DATA0_PIN;
  GPIO_Init(DATA_GPIO, &GPIO_Structure);
  GPIO_Structure.GPIO_Pin = DATA1_PIN;
  GPIO_Init(DATA_GPIO, &GPIO_Structure);
  GPIO_Structure.GPIO_Pin = DATA2_PIN;
  GPIO_Init(DATA_GPIO, &GPIO_Structure);
  GPIO_Structure.GPIO_Pin = DATA3_PIN;
  GPIO_Init(DATA_GPIO, &GPIO_Structure);
  GPIO_Structure.GPIO_Pin = DATA4_PIN;
  GPIO_Init(DATA_GPIO, &GPIO_Structure);
  GPIO_Structure.GPIO_Pin = DATA5_PIN;
  GPIO_Init(DATA_GPIO, &GPIO_Structure);
  GPIO_Structure.GPIO_Pin = DATA6_PIN;
  GPIO_Init(DATA_GPIO, &GPIO_Structure);
  GPIO_Structure.GPIO_Pin = DATA7_PIN;
  GPIO_Init(DATA_GPIO, &GPIO_Structure);
}
void LCD_Init(void)
{
  GPIO_InitConifg();
  LCD_WriteCon(CLOSE_CURSOR);         // 设置光标闪烁
  LCD_WriteCon(SHOW_TWO_5X7);         // 一行,5X7
  LCD_WriteCon(AFTER_CR);             // 光标左移,屏幕不移动
  LCD_WriteCon(CLEAR);                // 清屏
}
// 发送数据
void LCD_WriteData(uint_8 data)
{
  GPIO_ResetBits(CON_GPIO, CON_E_PIN);
  // 10, 写入数据
  GPIO_SetBits(CON_GPIO, CON_RS_PIN);
  GPIO_ResetBits(CON_GPIO, CON_RW_PIN);
  // 写入数据
  GPIO_Write(DATA_GPIO, data<<8);
  LCD_Desplay(0xffff);
  // 写入使能
  GPIO_SetBits(CON_GPIO, CON_E_PIN);
  LCD_Desplay(0xffff);
  GPIO_ResetBits(CON_GPIO, CON_E_PIN);
}
// 发送指令
void LCD_WriteCon(uint_8 data)
{
  GPIO_ResetBits(CON_GPIO, CON_E_PIN);
  // 00, 写入命令
  GPIO_ResetBits(CON_GPIO, CON_RS_PIN);
  GPIO_ResetBits(CON_GPIO, CON_RW_PIN);
  // 写入数据
  GPIO_Write(DATA_GPIO, data<<8);
  LCD_Desplay(0xffff);
  // 写入使能
  GPIO_SetBits(CON_GPIO, CON_E_PIN);
  LCD_Desplay(0xffff);
  GPIO_ResetBits(CON_GPIO, CON_E_PIN);
} 

串口驱动代码(移植于指南者例程)

头文件

 #ifndef __USART_H_
 #define __USART_H_
 #include "stm32f10x.h"
 #include "stdio.h"
 #define DEBUG1 1
 #define DEBUG_USART_BAUDRATE 115200
 // 串口对应的DMA请求通道
 #define  USART_TX_DMA_CHANNEL     DMA1_Channel5
 // 外设寄存器地址
 #define  USART_DR_ADDRESS        (USART1_BASE+0x04)
 // 一次发送的数据量
 #define  RECEIVEBUFF_SIZE            5000
 #ifdef DEBUG1
 // 串口 1-USART1
 #define DEBUG_USARTx USART1
 #define DEBUG_USART_CLK RCC_APB2Periph_USART1
 #define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
 // USART GPIO 引脚宏定义
 #define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
 #define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
 #define DEBUG_USART_TX_GPIO_PORT GPIOA
 #define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
 #define DEBUG_USART_RX_GPIO_PORT GPIOA
 #define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
 #define DEBUG_USART_IRQ USART1_IRQn
 #define DEBUG_USART_IRQHandler USART1_IRQHandler
 #elif DEBUG2
 // 串口2
 #define DEBUG_USARTx USART2
 #define DEBUG_USART_CLK RCC_APB1Periph_USART2
 #define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
 // USART GPIO 引脚宏定义
 #define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
 #define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
 #define DEBUG_USART_TX_GPIO_PORT GPIOA
 #define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_2
 #define DEBUG_USART_RX_GPIO_PORT GPIOA
 #define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_3
 #define DEBUG_USART_IRQ USART2_IRQn
 #define DEBUG_USART_IRQHandler USART2_IRQHandler
 #elif DEBUG3
 // 串口3
 #define DEBUG_USARTx USART3
 #define DEBUG_USART_CLK RCC_APB1Periph_USART3
 #define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
 // USART GPIO 引脚宏定义
 #define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOB)
 #define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
 #define DEBUG_USART_TX_GPIO_PORT GPIOB
 #define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
 #define DEBUG_USART_RX_GPIO_PORT GPIOB
 #define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
 #define DEBUG_USART_IRQ USART3_IRQn
 #define DEBUG_USART_IRQHandler USART3_IRQHandler
 #elif DEBUG4
 // 串口4
 #define DEBUG_USARTx USART4
 #define DEBUG_USART_CLK RCC_APB1Periph_USART4
 #define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
 // USART GPIO 引脚宏定义
 #define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC)
 #define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
 #define DEBUG_USART_TX_GPIO_PORT GPIOC
 #define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
 #define DEBUG_USART_RX_GPIO_PORT GPIOC
 #define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
 #define DEBUG_USART_IRQ USART4_IRQn
 #define DEBUG_USART_IRQHandler USART4_IRQHandler
 #elif DEBUG5
 // 串口5
 #define DEBUG_USARTx USART5
 #define DEBUG_USART_CLK RCC_APB1Periph_USART5
 #define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
 // USART GPIO 引脚宏定义
 #define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC)
 #define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
 #define DEBUG_USART_TX_GPIO_PORT GPIOC
 #define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_12
 #define DEBUG_USART_RX_GPIO_PORT GPIOD
 #define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_2
 #define DEBUG_USART_IRQ USART5_IRQn
 #define DEBUG_USART_IRQHandler USART5_IRQHandler
 // 打开串口GPIOD的时钟
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
 #endif
 static void NVIC_Configuration(void);
 void DEBUG_Config(void);
 void Usart_SendByte(USART_TypeDef* pUSARTX, char data);
 void Usart_SendString( USART_TypeDef * pUSARTx, char *str);
 int fputc(int ch, FILE *f);
 int fgetc(FILE *f);
 #endif

源文件

  #include "usart.h"
__IO unsigned char ReceiveBuff[RECEIVEBUFF_SIZE];
static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  /* 嵌套向量中断控制器组选择 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  /* 配置 USART 为中断源 */
  NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
  /* 抢断优先级为 1 */
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 子优先级为 1 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  /* 初始化配置 NVIC */
  NVIC_Init(&NVIC_InitStructure);
}
// 初始化UART-DMA
static void DMA_Configuration()
{
    DMA_InitTypeDef DMA_InitStructure;
    // 开启DMA时钟
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    // 设置DMA源地址:串口数据寄存器地址*/
    DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_ADDRESS;
    // 内存地址(要传输的变量的指针)
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ReceiveBuff;
    // 方向:从外设到内存  
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    // 传输大小 
    DMA_InitStructure.DMA_BufferSize = RECEIVEBUFF_SIZE;
    // 外设地址不增     
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    // 内存地址自增
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    // 外设数据单位 
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    // 内存数据单位
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;  
    // DMA模式,一次或者循环模式
    //    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; 
    // 优先级:中  
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; 
    // 禁止内存到内存的传输
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    // 配置DMA通道       
    DMA_Init(USART_TX_DMA_CHANNEL, &DMA_InitStructure);   
    // 使能DMA
    DMA_Cmd (USART_TX_DMA_CHANNEL, ENABLE);
}
void DEBUG_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
  // 打开串口 GPIO 的时钟
  DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
  // 打开串口外设的时钟
  DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
  // 将 USART Tx 的 GPIO 配置为推挽复用模式
  GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
  // 将 USART Rx 的 GPIO 配置为浮空输入模式
  GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
  // 配置串口的工作参数
  // 配置波特率
  USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
  // 配置 针数据字长
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  // 配置停止位
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  // 配置校验位
  USART_InitStructure.USART_Parity = USART_Parity_No ;
  // 配置硬件流控制
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  // 配置工作模式,收发一起
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  // 完成串口的初始化配置
  USART_Init(DEBUG_USARTx, &USART_InitStructure);
  // 串口中断优先级配置
  NVIC_Configuration();
  // 使能串口接收中断
  USART_ITConfig(DEBUG_USARTx, USART_IT_IDLE, ENABLE);
  // 使能串口
  USART_Cmd(DEBUG_USARTx, ENABLE);
  // 串口DMA配置
  DMA_Configuration();
  /* USART1 向 DMA发出RX请求使能 */
  USART_DMACmd(DEBUG_USARTx, USART_DMAReq_Rx, ENABLE);
}
void Usart_SendByte(USART_TypeDef* pUSARTx, char data)
{
  USART_SendData(pUSARTx, data);
  while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
  unsigned int k=0;
  do {
    Usart_SendByte( pUSARTx, *(str + k) );
    k++;
  } while (*(str + k)!='\0');
  /* 等待发送完成 */
  while (USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET) {
  }
}
//重定向fputc函数
int fputc(int ch, FILE *f)
{
  Usart_SendByte(DEBUG_USARTx, (unsigned char)ch);
  while(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
  return (ch);
}
int fgetc(FILE *f)
{
  while(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
  return (int) USART_ReceiveData(DEBUG_USARTx);
}

主函数

#include "stm32f10x.h"
#include "usart.h"
#include "lcd.h"
#include <string.h>
extern __IO unsigned char ReceiveBuff[RECEIVEBUFF_SIZE];
unsigned char data[] = "xiaodong, Hello World!";
char index = 0;
void delay(unsigned int a)
{
  while(a--);
}
int main(void)
{
  int i = 0;
  //LED_init();
  DEBUG_Config();
  LCD_Init();
//  for (i=0;i<strlen((char *)data);i++) {
//    if (i==16) {
//      printf("正在换行\n");
//      LCD_WriteCon(0xC0);
//    }
//    LCD_WriteData(data[i]);
//  }
  //printf("sdf");
  while(1);
}
void DEBUG_USART_IRQHandler(void)
{
  int i = 0;
  int t = 0;
  if (USART_GetITStatus(DEBUG_USARTx,USART_IT_IDLE) == SET) {
    DMA_Cmd(USART_TX_DMA_CHANNEL,DISABLE);                         //关闭DMA传输
    t = DMA_GetCurrDataCounter(USART_TX_DMA_CHANNEL);              //获取剩余的数据数量
    //Usart_SendArray(DEBUG_USARTx,ReceiveBuff,RECEIVEBUFF_SIZE-t);  //向电脑返回数据(接收数据数量 = SENDBUFF_SIZE - 剩余未传输的数据数量)
    // 显示数据
    printf("数据长度: %d\n", RECEIVEBUFF_SIZE-t);
    for (i=0;i<RECEIVEBUFF_SIZE-t;i++) {
      if (index % 32 == 0 && index != 0) {
        LCD_WriteCon(0x80);
        index = 0;
      } else if (index % 16 == 0 && index != 0) {
        LCD_WriteCon(0xC0);
      }
      LCD_WriteData(ReceiveBuff[i]);
      //printf("%c", ReceiveBuff[i]);
      index++;
    }
    DMA_SetCurrDataCounter(USART_TX_DMA_CHANNEL,RECEIVEBUFF_SIZE); //重新设置传输的数据数量
    DMA_Cmd(USART_TX_DMA_CHANNEL,ENABLE);                          //开启DMA传输
    USART_ReceiveData(DEBUG_USARTx);                              //读取一次数据,不然会一直进中断
    USART_ClearFlag(DEBUG_USARTx,USART_IT_IDLE);
  }
}

5. 效果


c5767405761b4881b042403034c82a4e.png


dc5e36414eff42bb8b4285350e98d23c.png

目录
相关文章
STM32Cubemx PWM驱动加湿器模拟火山喷发效果
STM32Cubemx PWM驱动加湿器模拟火山喷发效果
371 14
STM32Cubemx PWM驱动SG90舵机
STM32Cubemx PWM驱动SG90舵机
853 13
STM32CubeMX mpu6050驱动
STM32CubeMX mpu6050驱动
266 10
STM32CubeMX EC11旋转编码器驱动
STM32CubeMX EC11旋转编码器驱动
1524 10
STM32CubeMX OLED驱动
STM32CubeMX OLED驱动
291 10
|
芯片
STM32CubeMX TM1637驱动数码管
STM32CubeMX TM1637驱动数码管
1051 6
STM32CubeMX WS2812B灯驱动
STM32CubeMX WS2812B灯驱动
1350 1