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 // 显示两行,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. 效果