使用stm32f103驱动lcd1602

1. 项目需求

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

2. 使用到的软件和硬件

  • 野火指南者开发板 - LCD1602液晶屏
    使用stm32f103驱动lcd1602_第1张图片
  • 杜邦线
  • DAP仿真器
  • KEIL5

3. 连线说明使用stm32f103驱动lcd1602_第2张图片

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);
    }	
    
    
  2. 串口驱动代码(移植于指南者例程)
    头文件
     #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);
    }
    
  3. 主函数
    #include "stm32f10x.h"
    #include "usart.h"
    #include "lcd.h"
    #include 
    
    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
    //		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. 效果

使用stm32f103驱动lcd1602_第3张图片
使用stm32f103驱动lcd1602_第4张图片

你可能感兴趣的:(STM32&51单片机,c语言,stm32)