使用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

目录
相关文章
小巴陪你搞技术-STM32驱动1602时钟
小巴陪你搞技术-STM32驱动1602时钟
|
20天前
|
传感器
手把手在STM32F103C8T6上构建可扩展可移植的DHT11驱动
【8月更文挑战第29天】本文详细介绍在STM32F103C8T6上构建可扩展且可移植的DHT11温湿度传感器驱动的步骤,包括硬件与软件准备、硬件连接、驱动代码编写及测试。通过这些步骤,可根据实际项目需求优化和扩展代码。
|
2月前
STM32Cubemx PWM驱动加湿器模拟火山喷发效果
STM32Cubemx PWM驱动加湿器模拟火山喷发效果
50 14
|
2月前
STM32Cubemx PWM驱动SG90舵机
STM32Cubemx PWM驱动SG90舵机
78 13
|
2月前
STM32CubeMX mpu6050驱动
STM32CubeMX mpu6050驱动
44 10
|
2月前
STM32CubeMX EC11旋转编码器驱动
STM32CubeMX EC11旋转编码器驱动
54 10
|
2月前
STM32CubeMX OLED驱动
STM32CubeMX OLED驱动
47 10
|
2月前
|
芯片
STM32CubeMX TM1637驱动数码管
STM32CubeMX TM1637驱动数码管
47 6
|
2月前
STM32CubeMX WS2812B灯驱动
STM32CubeMX WS2812B灯驱动
68 1