嵌入式学习---串口篇

目录

1. 串行并行

2. UART

3. 串口重定向

4. UART通信实现

 

 

1. 串行并行

串口,全称为串行通信接口(Serial Communication Interface),是一种计算机硬件设备用于与其他设备进行数据传输的接口。与串行通信对应的是并行通信,在这里也一并说一说。

串行通信

  • 定义:串行通信是指数据以一位一位的顺序进行传输的方式。
  • 特点
    • 使用较少的线路资源,通常只需要一条数据线加上必要的控制和时钟信号线。
    • 适合长距离传输,因为减少了线路间的干扰。
    • 传输速度相对较慢,因为一次只能传输一位数据。
    • 实现起来比较简单,成本较低。
  • 应用:广泛应用于计算机与外部设备之间的通信,如 RS-232、USB、SPI、I²C 等。

并行通信

  • 定义:并行通信是指数据以多位同时进行传输的方式。
  • 特点
    • 使用较多的线路资源,通常需要多条数据线同时传输多位数据。
    • 适合短距离传输,因为多条线路容易受到干扰。
    • 传输速度较快,因为一次可以传输多位数据。
    • 实现起来相对复杂,成本较高。
  • 应用:主要用于计算机内部组件之间的通信,如早期的打印机端口(LPT)、PCI 总线等。

小结:

  • 串行通信:适合长距离、低成本的应用场景,如远程通信和嵌入式系统。
  • 并行通信:适合短距离、高速度的应用场景,如计算机内部组件之间的通信。

2. UART

在STM32单片机中,集成了一种片上外设,USART(Universal Synchronous/Asynchronous Receiver/Transmitter",通用同步/异步接收/发送器),是一种全双工通用同步/异步串行收发模块,它是串口通信的一种具体实现。支持同步和异步模式下的数据传输,可以灵活地与外部设备进行全双工数据交换。

而UART(Universal Asynchronous Receiver/Transmitter,通用异步接收/发送器)是USART去掉同步功能(时钟)后的一种通信方式。因为去掉了时钟,使得其通信更为简单方便(不需要考虑同步时钟),得到了更广泛的应用。

  • 定义:UART 是一种用于实现异步串行通信的硬件接口,它支持全双工通信,即可以同时发送和接收数据。
  • 特点
    • 支持异步通信,不需要外部时钟信号同步。
    • 通常使用两条线路:TX(发送)和 RX(接收)。
    • 支持多种波特率和数据格式。
    • 包含数据位、起始位、停止位以及可选的奇偶校验位。
  • 应用:广泛应用于微控制器、计算机与外设之间的通信,如 RS-232、USB 等接口。

UART/USART通信接线示意图:

3. 串口重定向

串口重定向是一种技术手段,用于改变串口数据的流向使得原本应该通过串口输出的数据被导向到其他地方,比如文件、网络或其他设备。串口重定向可以应用于不同的场景,包括但不限于终端服务器、嵌入式系统开发和调试等。

在C语言中有一个输出函数printf (),通常通过标准输出 stdout 输出数据到控制台,我们通过将 stdout 重定向到串口,可以实现 printf 的串口输出。

这样做的目的是为了能够在没有显示器的情况下也能查看调试信息,这对于嵌入式开发特别有用。

实现方法 1:

(1)重写fputc函数:

  • printf 函数底层调用 fputc 函数来输出字符。
  • 通过重新定义 fputc 函数,使其将字符通过串口发送出去,就可以实现 printf 的串口重定向。

(2)配置 Micro-LIB

  • 在魔术棒选项卡中,勾选 use Micro-LIB 选项。
  • 这样可以启用 Micro-LIB,它是一个小型的 C 标准库,用于嵌入式系统。

(3)添加标准输入输出

  • 在 main.c 文件中添加标准输入输出相关的头文件。
  • #include <stdio.h>    #include <stdlib.h>

实现方法 2:

加入以下代码,不需要勾选use MicroLIB。

#pragma import(__use_no_semihosting)             
/*********************************************************************
 @Function  : 标准库需要的支持函数 
 @Parameter : N/A
 @Return    : N/A
**********************************************************************/              
struct __FILE 
{ 
	int handle; 
}; 

FILE __stdout;   

/*********************************************************************
 @Function  : 定义_sys_exit()以避免使用半主机模式
 @Parameter : X :
 @Return    : N/A
**********************************************************************/   
void _sys_exit(int x) 
{ 
	x = x; 
} 

/*********************************************************************
 @Function  : 重定义fputc函数
 @Parameter : ch :入口数据
							 f :入口指针
 @Return    : ch :入口数据
**********************************************************************/
int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;      
	return ch;
}

4. UART通信实现

初始化配置没有太多好说的,就是片上外设的配置,需要什么中断就开哪个中断,并在串口中断处理函数里做相应处理就行了。

要说的几点:

(1)输出引脚配置为复用,因为是把原本的通用IO功能,用作片上外设UART的Tx功能,所以是复用。一般来讲,只要是把原本的通用IO接到片上外设做输出,就是复用

2)输入引脚配置为浮空,因为要接收的数据有高又有低。不能上下拉,那样会使它保持到高或低,无法正确接收数据。

串口初始化配置:

void USART1_Init(uint32_t Baud)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef  NVIC_InitStructure;
    /*时钟使能*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | \
												 RCC_APB2Periph_GPIOA, ENABLE);	
	/*引脚复用*/  //PA9->TXD 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	//PA10->RXD
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA, &GPIO_InitStructure); 
	/*NVIC 配置*/
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2 ;//抢占优先级2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //子优先级2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			
	NVIC_Init(&NVIC_InitStructure);		
    /*USART设置*/
	USART_InitStructure.USART_BaudRate = Baud;  //波特率,根据需求自己选
	USART_InitStructure.USART_WordLength = USART_WordLength_8b; //发8位数据
	USART_InitStructure.USART_StopBits = USART_StopBits_1; //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_ITConfig(USART1,USART_IT_IDLE,ENABLE);  //开空闲中断
//	USART_ITConfig(USART1,USART_IT_TXE,ENABLE);   //开发送中断	
    USART_Cmd(USART1, ENABLE); 
}

串口发送数据与字符串:

*Data++就是一个后++生效时间的问题,当前语句时++没加上(后++:首先返回 Data 的当前值,然后将 Data 的值增加,增加的时候已经执行到第二句了),因此这个语句是先访问Data指向的首地址的内容,再访问Data指向的下一地址的内容,直到结束。

//发送数据
void USART_SendByte(USART_TypeDef* USARTx, uint8_t* Data,uint8_t len)
{
	uint8_t  i = 0;
	for(i=0;i<len;i++)
	{
		while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) != SET);
		USART_SendData(USARTx,*Data++);
	}
}
//发送字符串
void USART_Send_String(USART_TypeDef* USARTx, const uint8_t* str)
{
	while(*str != '\0')  //字符串自带一个结束标志'\0',等于这个代表字符发完了
	{
		while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) != SET);
		USART_SendData(USARTx,*str++);
	}
}

串口中断处理函数 :

//串口1中断服务程序
void USART1_IRQHandler(void)               
{
    u8 r = 0;
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断
    {
        r = USART_ReceiveData(USART1);         //读取接收到的数据
        while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) != SET);
        USART_SendData(USART1,r);  //原样发回
    }
    USART_ClearFlag(USART1,USART_FLAG_TXE);  //清除标志位,标志位有的是硬件自动清除的,记不住就手动再清一遍
}

到此,串口的数据收发就实现了。

在嵌入式系统中,串口除了进行基本通信外,还可用于调试,是一个十分重要的必备外设。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值