1. 项目需求
- 使用上位机发送ASCII字符,在LCD1602上能够实时显示
2. 使用到的软件和硬件
- 野火指南者开发板 - LCD1602液晶屏
- 杜邦线
- DAP仿真器
- KEIL5
3. 连线说明
4. 代码
- 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 // 显示两行,5X10void 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); // 一行,5X7LCD_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);#endifstatic 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); // 使能DMADMA_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. 效果