【uFun试用体验】串口通信(1)

通信,按照传统的理解就是信息的传输与交换。对于单片机来说,通信则与传感器、存储芯片、外围控制芯片等技术紧密结合,成为整个单片机系统的“神经中枢”。没有通信,单片机所实现的功能仅仅局限于单片机本身,就无法通过其它设备获得有用信息,也无法将自己产生的信息告诉其它设备。如果单片机通信没处理好的话,它和外围器件的合作程度就受到限制,最终整个系统也无法完成强大的功能,由此可见单片机通信技术的重要性。 UART(Universal Asynchronous Receiver/Transmitter,即通用异步收发器)串行通信是单片机最常用的一种通信技术,通常用于单片机和电脑之间以及单片机和单片机之间的通信。
通信可以简单的分为并行通信和串行通信。并行通信传输数据是各个位同时传送,可以实现字节为单位通信,但是通信线占用的资源多成本高。同时不适合远距离通信。
stm32f103使用并口可以使用标准库函数GPIO的GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);一次给 P0 的 16个 IO 口分别赋值,同时进行信号输出,类似于有 16 个车道同时可以过去 816辆车一样,这种形式就是并行的;而串行通信,就如同一条车道,一次只能一辆车过去,如果一个 0xFE 这样一个字节的数据要传输过去的话,假如低位在前高位在后的话,那发送方式就是 0-1-1-1-1-1-1-1-1,一位一位的发送出去的,要发送 8 次才能发送完一个字节。
STM32F103VET6 系统控制器有三个 USART 和两个 UART,其中 USART1 和时钟来源于 APB2 总线时钟,其最大频率为 72MHz,其他四个的时钟来源于 APB1 总线时钟,其最大频率为 36MHz。 UART 只是异步传输功能,所以没有 SCLK、 nCTS 和 nRTS 功能引脚。
TX:发送数据输出引脚。
RX:接收数据输入引脚。
SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。
nCTS:清除以发送(Clear To Send), n表示低电平有效。如果使能 CTS 流控制,发送器在发送下一帧数据之前会检测 nCTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完当前数据帧之后停止发送。该引脚只适用于硬件流控制。
nRTS:请求以发送(Request To Send), n 表示低电平有效。如果使能 RTS 流控制,当USART 接收器准备好接收新数据时就会将 nRTS 变成低电平;当接收寄存器已满时, nRTS将被设置为高电平。该引脚只适用于硬件流控制。
对应引脚

但是在这个开发板中,不需要硬件控制。
再说一下通信的基本类型
常用的通信从传输方向上可以分为单工通信、半双工通信、全双工通信三类。
单工通信就是指只允许一方向另外一方传送信息,而另一方不能回传信息。比如电视遥控器、收音机广播等,都是单工通信技术。如果串口只用一个收发,可以说是单工通信。
半双工通信是指数据可以在双方之间相互传播,但是同一时刻只能其中一方发给另外一方,比如我们的对讲机就是典型的半双工。
全双工通信就发送数据的同时也能够接收数据,两者同步进行,就如同我们的电话一样,我们说话的同时也可以听到对方的声音。
下面是代码

#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_usart.h"
#include <stdio.h>
/*这个板子的晶振是12M,需要改一下时钟
具体操作
将stm32f10xx.h 124行的HSE_VALUE    ((uint32_t)8000000)改为HSE_VALUE    ((uint32_t)12000000) 
将system_stm32f10x.c 1054行的 RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9)改为
 RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL6);*/
void USART_NVIC_config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure; //开启串口中断
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断向量组
  	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //中断源设置
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //优先级设置
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //抢占优先级设置
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //中断通道使能
	NVIC_Init(&NVIC_InitStructure); //初始化串口中断
}

/*
	串口引脚的分布
	USART1: RX PA10 TX PA9
	USART2:  RX PA3  TX PA2
	USART3:  RX PB11 TX PB10
	UART4:   RX PC11 TX PC10
	UART5:   RX PD2  TX PC12
*/
void usart_config(void) 
{
	GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO结构体
	USART_InitTypeDef USART_InitStructure; //定义串口结构体
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //开启串口时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIO时钟
	
	//设置TXD为复用输出模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //
	GPIO_Init(GPIOA, &GPIO_InitStructure); //
	
	//设置RXD为输入模式
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IN_FLOATING; //
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //
	GPIO_Init(GPIOA, &GPIO_InitStructure); //
	
	USART_InitStructure.USART_BaudRate = 9600; //设置波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b; //设置串口长度
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //不使用硬件流控制
	USART_InitStructure.USART_Parity = USART_Parity_No; //设置为无校验位
	USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位为一
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //设置串口模式为发生与接收
	USART_Init(USART1, &USART_InitStructure); //初始化串口
	USART_NVIC_config(); //配置串口中断
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //打开串口接收中断 
	USART_Cmd(USART1, ENABLE); //串口使能
}

int main(void)
{
	usart_config();
	printf("一个回显程序");
	while(1)
	{
	}
}

void USART1_IRQHandler()
{
	uint8_t tmp;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //如果串口标志位成立
	{
		 tmp = USART_ReceiveData(USART1); //接收数据
		 USART_SendData(USART1, tmp); //发送数据
	}
}

///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
		/* 发送一个字节数据到串口 */
		USART_SendData(USART1, (uint8_t) ch);
		
		/* 等待发送完毕 */
		while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}

///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
		/* 等待串口输入数据 */
		while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);

		return (int)USART_ReceiveData(USART1);
}
发布了25 篇原创文章 · 获赞 19 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/little_engineer/article/details/89919328
今日推荐