历史上的今天
返回首页

历史上的今天

今天是:2025年04月12日(星期六)

2019年04月12日 | STM32F4 USART1 TX RX FIFO

2019-04-12 来源:eefocus

USART1 TX RX FIFO


/*

*********************************************************************************************************

*                                   

* 模块名称 : 串口驱动模块    

* 文件名称 : bsp_uart.c

* 版    本 : V1.0

* 说    明 : 实现printf和scanf函数重定向到串口1,即支持printf信息到USART1

* 实现重定向,只需要添加2个函数:

* int fputc(int ch, FILE *f);

* int fgetc(FILE *f);

* 对于KEIL MDK编译器,编译选项中需要在MicorLib前面打钩,否则不会有数据打印到USART1。

* 修改记录 :

* 版 本 库 : ST固件库V1.0.2版本。

*

*********************************************************************************************************

*/

//#include "stm32f4xx.h"

#include "bspdebug_usartbsp_debug_uart.h"

#include "bsp.h"

#include

#define  debug_uart_tx_buf_size  1*1024

#define  debug_uart_rx_buf_size  1*1024

static uint8_t g_TxBuf[debug_uart_tx_buf_size];  //发送缓冲区

static uint8_t g_RxBuf[debug_uart_rx_buf_size];  //接受缓冲区

/* 串口设备结构体 */

typedef struct

{

  USART_TypeDef *uart; /* STM32内部串口设备指针*/

uint8_t *pTxBuf;   /* 发送缓冲区 */

uint8_t *pRxBuf; /* 接收缓冲区 */

uint16_t usTxBufSize; /* 发送缓冲区大小 */

uint16_t usRxBufSize; /* 接收缓冲区大小 */


uint16_t usTxWrite; /* 发送缓冲区写指针 */

uint16_t usTxRead; /* 发送缓冲区读指针 */

uint16_t usTxCount; /* 等待发送的数据个数 */

 

uint16_t usRxWrite; /* 接收缓冲区写指针 */

uint16_t usRxRead; /* 接收缓冲区读指针 */

uint16_t usRxCount; /* 还未读取的新数据个数 */

 

void (*SendBefor)(void); /* 开始发送之前的回调函数指针(主要用于RS485切换到发送模式) */

void (*SendOver)(void); /* 发送完毕的回调函数指针(主要用于RS485将发送模式切换为接收模式) */

void (*ReciveNew)(void); /* 串口收到数据的回调函数指针 */

}UART_T;

 

static UART_T g_tDebugUart;

 

static void UartVarInit(void)

{

g_tDebugUart.uart=USART1;

g_tDebugUart.pTxBuf = g_TxBuf; /* 发送缓冲区指针 */

g_tDebugUart.pRxBuf = g_RxBuf; /* 接收缓冲区指针 */

g_tDebugUart.usTxBufSize = debug_uart_tx_buf_size; /* 发送缓冲区大小 */

g_tDebugUart.usRxBufSize = debug_uart_rx_buf_size; /* 接收缓冲区大小 */


g_tDebugUart.usTxWrite = 0; /* 发送FIFO写索引 */

g_tDebugUart.usTxRead = 0; /* 发送FIFO读索引 */

g_tDebugUart.usRxWrite = 0; /* 接收FIFO写索引 */

g_tDebugUart.usRxRead = 0; /* 接收FIFO读索引 */

g_tDebugUart.usRxCount = 0; /* 接收到的新数据个数 */

g_tDebugUart.usTxCount = 0; /* 待发送的数据个数 */


g_tDebugUart.SendBefor = 0; /* 发送数据前的回调函数 */

g_tDebugUart.SendOver = 0; /* 发送完毕后的回调函数 */

g_tDebugUart.ReciveNew = 0; /* 接收到新数据后的回调函数 */

}

 

static void ConfigUartNVIC(void)

{

NVIC_InitTypeDef NVIC_InitStructure;

  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

}

 

 

 

/*

*********************************************************************************************************

* 函 数 名: bsp_InitUart

* 功能说明: 初始化CPU的USART1串口硬件设备。未启用中断。

* 形    参:无

* 返 回 值: 无

*********************************************************************************************************

*/

void bsp_InitDebugUart(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

USART_InitTypeDef USART_InitStructure;


UartVarInit();

ConfigUartNVIC();

/* 串口1 TX = PA9   RX = PA10 */

 

/* 第1步: 配置GPIO */

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);/* 打开 GPIO 时钟 */

/* 打开 UART 时钟 */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

/* 将 PA9 映射为 USART1_TX */

GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);

/* 将 PA10 映射为 USART1_RX */

GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);

 

/* 配置 USART Tx 为复用功能 */

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; /* 输出类型为推挽 */

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; /* 内部上拉电阻使能 */

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; /* 复用模式 */

 

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

 

/* 配置 USART Rx 为复用功能 */

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

GPIO_Init(GPIOA, &GPIO_InitStructure);

 

/* 第2步: 配置串口硬件参数 */

USART_InitStructure.USART_BaudRate = 115200; /* 波特率 */

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(USART1, &USART_InitStructure);

  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); /* 使能接收中断 */

USART_Cmd(USART1, ENABLE); /* 使能串口 */

 

/* CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去

如下语句解决第1个字节无法正确发送出去的问题 */

USART_ClearFlag(USART1, USART_FLAG_TC);     /* 清发送完成标志,Transmission Complete flag */   

}

 

void comSendChar(int ch)

{

if(g_tDebugUart.SendBefor!=0)//开始回调前调用回调函数

{

g_tDebugUart.SendBefor();

}

while(1)

{

uint16_t usRead;

DISABLE_INT();

usRead = g_tDebugUart.usTxCount;

ENABLE_INT();

if( usRead < g_tDebugUart.usTxBufSize)//如果发送缓冲区域的满则等待

{

break;

}

}

g_tDebugUart.pTxBuf[g_tDebugUart.usTxWrite]= ch;//向发送缓存区写入数值

DISABLE_INT();

if (++g_tDebugUart.usTxWrite >= g_tDebugUart.usTxBufSize)//发送指针加一

{

g_tDebugUart.usTxWrite = 0;

}

g_tDebugUart.usTxCount++;//发送数加一

ENABLE_INT();

USART_ITConfig(g_tDebugUart.uart, USART_IT_TXE, ENABLE);



 

 

}

/*

*********************************************************************************************************

* 函 数 名: UartGetChar

* 功能说明: 从串口接收缓冲区读取1字节数据 (用于主程序调用)

* 形    参: _pUart : 串口设备

*   _pByte : 存放读取数据的指针

* 返 回 值: 0 表示无数据  1表示读取到数据

*********************************************************************************************************

*/

uint8_t comGetChar( uint8_t *_pByte)

uint16_t usCount;

DISABLE_INT();

usCount = g_tDebugUart.usRxCount;

ENABLE_INT();

if(usCount==0)

{

return 0;

}

else

{

*_pByte = g_tDebugUart.pRxBuf[g_tDebugUart.usRxRead]; /* 从串口接收FIFO取1个数据 */

/* 改写FIFO读索引 */

DISABLE_INT();

if (++g_tDebugUart.usRxRead >= g_tDebugUart.usRxBufSize)

{

g_tDebugUart.usRxRead = 0;

}

g_tDebugUart.usRxCount--;

ENABLE_INT();

return 1;


}

 

}

/*

*********************************************************************************************************

* name: fputc 重定向printf

*********************************************************************************************************

*/

int fputc(int ch, FILE *f)

{

#if 1

comSendChar(ch);

return ch;

#else 

while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET){};

USART_SendData(USART1, (u16) ch);

return ch;

#endif 

}

 

/*

*********************************************************************************************************

*重定向getc

*********************************************************************************************************

*/

int fgetc(FILE *f)

{

#if 1

uint8_t ucData;

while(comGetChar(&ucData) == 0);

return ucData;


#else

while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);

return (int)USART_ReceiveData(USART1);

#endif 

}

 

 

 void USART1_IRQHandler(void)

{

/* 处理接收中断  */

if (USART_GetITStatus(g_tDebugUart.uart, USART_IT_RXNE) != RESET)

{

g_tDebugUart.pRxBuf[g_tDebugUart.usRxWrite] = USART_ReceiveData(g_tDebugUart.uart); /* 从串口接收数据寄存器读取数据存放到接收FIFO */

if (++g_tDebugUart.usRxWrite >= g_tDebugUart.usRxBufSize)

{

g_tDebugUart.usRxWrite = 0;

}

if (g_tDebugUart.usRxCount < g_tDebugUart.usRxBufSize)

{

g_tDebugUart.usRxCount++;

}

 

/* 回调函数,通知应用程序收到新数据,一般是发送1个消息或者设置一个标记 */

//if (_pUart->usRxWrite == _pUart->usRxRead)

if (g_tDebugUart.usRxCount == 1)

{

if (g_tDebugUart.ReciveNew)

{

g_tDebugUart.ReciveNew();

}

}

}

 

/* 处理发送缓冲区空中断 */

if (USART_GetITStatus(g_tDebugUart.uart, USART_IT_TXE) != RESET)

{

//if (_pUart->usTxRead == _pUart->usTxWrite)

if (g_tDebugUart.usTxCount == 0)

{

USART_ITConfig(g_tDebugUart.uart, USART_IT_TXE, DISABLE);/* 发送缓冲区的数据已取完时, 禁止发送缓冲区空中断 (注意:此时最后1个数据还未真正发送完毕)*/

USART_ITConfig(g_tDebugUart.uart, USART_IT_TC, ENABLE);/* 使能数据发送完毕中断 */

}

else

{

USART_SendData(g_tDebugUart.uart, g_tDebugUart.pTxBuf[g_tDebugUart.usTxRead]);/* 从发送FIFO取1个字节写入串口发送数据寄存器 */

if (++g_tDebugUart.usTxRead >= g_tDebugUart.usTxBufSize)

{

g_tDebugUart.usTxRead = 0;

}

g_tDebugUart.usTxCount--;

}

 

}

else if (USART_GetITStatus(g_tDebugUart.uart, USART_IT_TC) != RESET)/* 数据bit位全部发送完毕的中断 */

{

if (g_tDebugUart.usTxCount == 0)

{

USART_ITConfig(g_tDebugUart.uart, USART_IT_TC, DISABLE);/* 如果发送FIFO的数据全部发送完毕,禁止数据发送完毕中断 */

 

/* 回调函数, 一般用来处理RS485通信,将RS485芯片设置为接收模式,避免抢占总线 */

if (g_tDebugUart.SendOver)

{

g_tDebugUart.SendOver();

}

}

else

{

/* 正常情况下,不会进入此分支 */

/* 如果发送FIFO的数据还未完毕,则从发送FIFO取1个数据写入发送数据寄存器 */

USART_SendData(g_tDebugUart.uart, g_tDebugUart.pTxBuf[g_tDebugUart.usTxRead]);

if (++g_tDebugUart.usTxRead >= g_tDebugUart.usTxBufSize)

{

g_tDebugUart.usTxRead = 0;

}

g_tDebugUart.usTxCount--;

}

}

}

 

 

 

/***************************** (END OF FILE) *********************************/


推荐阅读

史海拾趣

骅讯(Cmedia)公司的发展小趣事

为了进一步提升品牌影响力和市场竞争力,骅讯积极寻求与知名品牌的合作。通过与音频市场上的主要品牌建立合作关系,骅讯成功将其先进的音频技术应用于各种音频产品中,为消费者带来了更为优质的音频体验。这种合作模式不仅促进了骅讯技术的推广和应用,也为其带来了更为广阔的市场空间。

EHC(ELECTRONICHARDWARE)公司的发展小趣事

EHC公司自创立之初就专注于电子硬件的技术创新。在竞争激烈的电子市场中,EHC公司凭借其独特的设计理念和先进的生产工艺,成功推出了一系列高性能、高可靠性的电子产品。这些产品不仅满足了消费者对高品质电子产品的需求,也为EHC公司赢得了良好的市场口碑。随着技术的不断进步,EHC公司不断推出创新产品,逐步巩固了其在行业中的领先地位。

宁波晨翔电子(CONNFLY)公司的发展小趣事

为了提高产品质量和客户满意度,晨翔电子高度重视质量管理体系建设。公司先后通过了ISO9001质量管理体系认证、ISO14001环境体系认证、OHSAS18001职业健康安全体系认证及TS16949汽车质量体系认证。这些认证不仅证明了公司在质量管理方面的实力,也为公司赢得了更多客户的信任和支持。

General Electric Solid State公司的发展小趣事

作为一家有社会责任感的企业,晨翔电子始终关注环保问题。公司在生产过程中积极采用环保材料和工艺,减少对环境的影响。同时,公司还积极参与社会公益活动,回馈社会。这些举措不仅体现了公司的环保意识和社会责任感,也为公司赢得了更多客户和社会的认可和支持。

Curtis Industries公司的发展小趣事

为了进一步扩大市场份额,Curtis Industries公司积极拓展市场布局。公司在全球范围内设立了多个生产基地和研发中心,以便更好地满足不同地区客户的需求。同时,公司还加强了与上下游企业的合作,形成了完整的产业链。这些举措不仅提升了公司的产能和研发实力,还为公司带来了更多的商业机会。

CW Industries公司的发展小趣事

CW Industries公司一直坚持从原材料到最终成品的完全一体化制造流程。这一制造模式使得公司能够对产品质量进行更严格的控制,并确保每一个生产环节的优化。为了进一步提高生产效率,CW Industries还引进了自动化设备,使得制造过程更加高效和精确。这种对生产流程的精细管理,让CW Industries在电子行业中树立了良好的口碑,并为公司的持续发展提供了有力保障。

问答坊 | AI 解惑

一个女电子工程师的(心/芯/辛)路

一个女电子工程师的(心/芯/辛)路,即将脱离技术岗位,仅以此文纪念吾之技术生涯 ( 首先我是女性,这个先声名,免得有些网友说俺用此做为噱头。) 同其他大多数女性一样,形象思维要好于逻辑思维。但我又与大多数女性不一样,我有我自己独 ...…

查看全部问答>

测振仪的技术原理及测振仪的技术问题

测振仪的技术原理及测振仪的技术问题 测振仪的技术原理, 测振仪的技术问题:     现在的测振仪一般都采用压电式的,结构形式大致有二种:① 压缩式;② 剪切式,其原理是利用石英晶体和人工极化陶瓷(PZT)的压电效应设计而成。当石 ...…

查看全部问答>

100分,请大家来给我启蒙,会唱歌的玩具娃娃

大家好,有人问到如何实现会唱歌的玩具娃娃,就和市面上的玩具娃娃一样,按一下,会唱首歌,再按一下会笑,再按会说话什么的,因为本人从来不涉及硬件设计知识,所以没办法回答朋友的问题,现在请大家告诉我下这个玩具娃娃是怎么个设计实现原理,谢 ...…

查看全部问答>

DIRECTSHOW preview时候改变图片显示的大小

我用DIRECTSHOW 想在 preview时候改变图片显示的大小? 哪位大吓知道?…

查看全部问答>

wince rtc开机

各路高手,请问WINCE通过RTC闹钟来实现定时开机要怎么做呀?原理是什么呀?注意不是通过RTC来唤醒系统哦,是开机!…

查看全部问答>

求助:我需要液体点滴的优秀作品

本帖最后由 paulhyde 于 2014-9-15 09:00 编辑 最近都在找资料,都没有找到关于液体点滴的优秀作品,哪位大侠有,请发我一份!谢谢!  …

查看全部问答>

再提供一个小作品:EK-STM3210E大容量仿真学习套件上市啦!

仿真器 - 内嵌ST-LINK II仿真器,支持STM32F10x标准系列和扩展总线系列Cortex-M3 MCU - USB2.0全速,USB供电 - 支持评估系统或用户目标系统仿真 - 下载速度大于5K/秒 - 通过跳线 ...…

查看全部问答>

STM8S103串口问题,两天了都

用的芯片是STM8S103F3.使用串口1,内部时钟,查询发送,中断或者查询接收疑问:STM8的管教复用是不是,你配置了串口,那么相应的两个管脚IO就自动成为RXD和TXD?现在的把收发两个管脚直接短路,程序里面一直在发送,用万用表测试电压为1.8V左右,估 ...…

查看全部问答>

读取DSP的IO口状态问题

请问,TI的28335DSP. 给GPIO配置为数字IO,且为输入,当给其输入高低电平的时候,为什么在GPxDAT寄存器中看到的状态和输入的状态不同,有时候改变输入电平后,但GPxDAT中的电平还是不变 [ 本帖最后由 kikihi 于 2012-12-15 14:36 编辑 ]…

查看全部问答>

雕刻机自制PCB电路板

雕刻机买回来一年多了,平时就是用来做一下外壳和五金件的样品加工,但从来没有用来做过PCB电路板,当时买这个机器的时候,同时也考虑做电路板的,所以在精度方面也考虑到了。尽管在机器的控制方面比较熟悉,但是第一次做电路板,尽管在参考了网上 ...…

查看全部问答>