⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uart_api.c

📁 STM32 三个串口同时使用(232/232/485)
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
* Copyright (C), 2010 安富莱电子 www.armfly.com
*
* 文件名: usart_api.c
* 内容简述: 使用中断方式实现串口FIFO,提供易用的函数接口,便于用户程序调用。
*			限STM32平台
*
* 文件历史:
* 版本号  日期       作者    说明
* v0.1    2010-09-05 armfly  创建该文件
*
*/

/*
	注意:
	(1) 中断程序未对发送缓冲区满做处理.也就是说调用comSendBuf()函数时,如果
		开辟的发送缓冲区不足,将导致最先放入FIFO的数据被冲掉。
		不过对以一般的应用程序,将发送缓冲区开的足够大以保证一个最长的通信帧能够容纳下即可。
*/

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdio.h>
#include "uart_api.h"

#define RS485_TX_Disable()	GPIO_ResetBits(GPIOF,  GPIO_Pin_10 | GPIO_Pin_11) /* 释放总线 */
#define RS485_TX_Enable()	GPIO_SetBits(GPIOF,  GPIO_Pin_10 | GPIO_Pin_11) 	/* 占用总线,准备发送 */

/* 定义3个串口结构体变量 */
static UART_T g_tUart1;
static UART_T g_tUart2;
static UART_T g_tUart3;

/* 定义各自的串口FIFO缓冲区 */
static uint8_t g_TxBuf1[UART1_TX_BUF_SIZE];
static uint8_t g_RxBuf1[UART1_RX_BUF_SIZE];

static uint8_t g_TxBuf2[UART2_TX_BUF_SIZE];
static uint8_t g_RxBuf2[UART2_RX_BUF_SIZE];

static uint8_t g_TxBuf3[UART3_TX_BUF_SIZE];
static uint8_t g_RxBuf3[UART3_RX_BUF_SIZE];

static void UartVarInit(void);
static void InitHardUart1(void);
static void InitHardUart2(void);
static void InitHardUart3(void);

static void RS485SendOver(void);
static void UartSend(UART_T *_pUart, uint8_t *_ucaBuf, uint16_t _usLen);
static uint8_t UartGetChar(UART_T *_pUart, uint8_t *_pByte);

/****************************************************************************
* 函数名: ConfigUartNVIC
* 功  能: 配置硬件中断.
* 输  入: 无
* 输  出: 无
* 返  回: 无
*/
static void ConfigUartNVIC(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  /* Configure the NVIC Preemption Priority Bits */  
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
  
  /* Enable the USART1 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  /* Enable the USART2 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  /* Enable the USART3 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

/****************************************************************************
* 函数名: comInit
* 功  能: 初始化串口硬件,并对全局变量赋初值.
* 输  入: 无
* 输  出: 无
* 返  回: 无
*/
void comInit(void)
{
	UartVarInit();		/* 必须先初始化全局变量,再配置硬件 */
	
	InitHardUart1();	/* 配置串口1的硬件参数 */
	InitHardUart2();	/* 配置串口2的硬件参数 */
	InitHardUart3();	/* 配置串口3的硬件参数 */

	ConfigUartNVIC();
}

/****************************************************************************
* 函数名: comSendBuf
* 功  能: 向串口发送一组数据,非阻塞。
* 输  入: 	_ucPort: 端口号(COM1 COM2 COM3)
*			_ucaBuf: 待发送的数据缓冲区
*			_usLen : 数据长度
* 输  出: 无
* 返  回: 无
*/
void comSendBuf(uint8_t _ucPort, uint8_t *_ucaBuf, uint16_t _usLen)
{
	UART_T *pUart;
		
	if (_ucPort == COM1)
	{
		pUart = &g_tUart1;
		
	}
	else if (_ucPort == COM2)
	{
		pUart = &g_tUart2;
	}
	else if (_ucPort == COM3)
	{
		pUart = &g_tUart3;

		RS485_TX_Enable();	/* 控制RS485芯片,准备发送数据 */
	}
	else
	{
		/* 不做任何处理 */
		return;
	}

	UartSend(pUart, _ucaBuf, _usLen);	
}

/****************************************************************************
* 函数名: comSendChar
* 功  能: 向串口发送1个字节,非阻塞。
* 输  入: 	_ucPort: 端口号(COM1 COM2 COM3)
*			_ucByte: 待发送的数据
* 输  出: 无
* 返  回: 无
*/
void comSendChar(uint8_t _ucPort, uint8_t _ucByte)
{
	comSendBuf(_ucPort, &_ucByte, 1);
}

/****************************************************************************
* 函数名: comGetChar
* 功  能: 从串口缓冲区读取1字节,非阻塞。
* 输  入: _pByte 结果存放地址
* 输  出: 无
* 返  回: 0 表示无数据, 1 表示读取到有效字节
*/
uint8_t comGetChar(uint8_t _ucPort, uint8_t *_pByte)
{
	UART_T *pUart;
	
	if (_ucPort == COM1)
	{
		pUart = &g_tUart1;
	}
	else if (_ucPort == COM2)
	{
		pUart = &g_tUart2;
	}
	else if (_ucPort == COM3)
	{
		pUart = &g_tUart3;
	}
	else
	{
		return 0;
	}
	
	return UartGetChar(pUart, _pByte);
}

/****************************************************************************
* 函数名: UartVarInit
* 功  能: 初始化串口相关的变量
* 输  入: 无
* 输  出: 无
* 返  回: 无
*/
static void UartVarInit(void)
{
	g_tUart1.uart = USART1;
	g_tUart1.pTxBuf = g_TxBuf1;
	g_tUart1.pRxBuf = g_RxBuf1;
	g_tUart1.usTxBufSize = UART1_TX_BUF_SIZE;
	g_tUart1.usRxBufSize = UART1_RX_BUF_SIZE;
	g_tUart1.usTxWrite = 0;
	g_tUart1.usTxRead = 0;
	g_tUart1.usRxWrite = 0;
	g_tUart1.usRxRead = 0;
	g_tUart1.SendOver = 0;	/* */
	g_tUart1.ReciveNew = 0;

	g_tUart2.uart = USART2;
	g_tUart2.pTxBuf = g_TxBuf2;
	g_tUart2.pRxBuf = g_RxBuf2;
	g_tUart2.usTxBufSize = UART2_TX_BUF_SIZE;
	g_tUart2.usRxBufSize = UART2_RX_BUF_SIZE;
	g_tUart2.usTxWrite = 0;
	g_tUart2.usTxRead = 0;
	g_tUart2.usRxWrite = 0;
	g_tUart2.usRxRead = 0;
	g_tUart2.SendOver = RS485SendOver;	/* RS485是半双工,因此数据发送完毕后,需要释放RS485总线 */
	g_tUart2.ReciveNew = 0;

	g_tUart3.uart = USART3;
	g_tUart3.pTxBuf = g_TxBuf3;
	g_tUart3.pRxBuf = g_RxBuf3;
	g_tUart3.usTxBufSize = UART3_TX_BUF_SIZE;
	g_tUart3.usRxBufSize = UART3_RX_BUF_SIZE;
	g_tUart3.usTxWrite = 0;
	g_tUart3.usTxRead = 0;
	g_tUart3.usRxWrite = 0;
	g_tUart3.usRxRead = 0;
	g_tUart3.SendOver = 0;
	g_tUart3.ReciveNew = 0;
}

/****************************************************************************
* 函数名: InitHardUart1
* 功  能: 配置UART1硬件参数
* 输  入: 无
* 返  回: 无
*/
static void InitHardUart1(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	USART_TypeDef *uart;

	/* 第1步:打开GPIO和USART部件的时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

	/* 第2步:将USART Tx的GPIO配置为推挽复用模式 */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	/* 第3步:将USART Rx的GPIO配置为浮空输入模式
		由于CPU复位后,GPIO缺省都是浮空输入模式,因此下面这个步骤不是必须的
		但是,我还是建议加上便于阅读,并且防止其它地方修改了这个口线的设置参数
	*/
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	/*  第3步已经做了,因此这步可以不做
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	*/
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	/* 第4步:设置串口硬件参数 */
	uart = USART1;	
	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(uart, &USART_InitStructure);
	USART_ITConfig(uart, USART_IT_RXNE, ENABLE);	/* 使能接收中断 */
	/* 
		USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
		注意: 不要在此处打开发送中断
		发送中断使能在SendUart()函数打开
	*/
	USART_Cmd(uart, ENABLE);		/* 使能串口 */ 

	/* CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去
		如下语句解决第1个字节无法正确发送出去的问题 */
	USART_ClearFlag(USART1, USART_FLAG_TC);     /* 清发送外城标志,Transmission Complete flag */
}

/****************************************************************************
* 函数名: InitHardUart2
* 功  能: 配置USART2硬件参数
* 输  入: 无
* 返  回: 无
*/
static void InitHardUart2(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -