系列文章目录
学习笔记:串口通信的概念以及编写程序实现串口通信。
遇到的…\OBJ\Project.axf: Error: L6200E: Symbol USART1_IRQHandler multiply defined (by usart.o and main.o).错误解决方法!
文章目录
前言
这两天在读《嵌入式C语言的自我修养》懂了很多知识,尤其是汇编和C的函数调用,这在学习串口进行通信的时候也用到了C语言调用汇编函数和NVIC中断程序的编写。
下面是我对知识的总结还有如何编写串口通信程序和NVIC中断程序的步骤(主要是参考了正点原子的参考手册)。
一、串口通信的基础知识
1.处理器与外部设备通信的两种方式:
并行通信
-传输原理:数据各个位同时传输。
-优点:速度快
-缺点:占用引脚资源多
串行通信
-传输原理:数据按位顺序传输。
-优点:占用引脚资源少
-缺点:速度相对较慢
1.1串行通信
按照数据传送方向,分为:
单工:
数据传输只支持数据在一个方向上传输。
半双工:
允许数据在两个方向上传输,但是,在某一时刻,只允许数
据在一个方向上传输,它实际上是一种切换方向的单工通信;
全双工:
允许数据同时在两个方向上传输,因此,全双工通信是两个
单工通信方式的结合,它要求发送设备和接收设备都有独立
的接收和发送能力。
串行通信三种传送方式:
1.2串行通信的通信方式
同步通信:带时钟同步信号传输。
-SPI,IIC通信接口;
异步通信:不带时钟同步信号。
-UART(通用异步收发器),单总线;
2.常见的串行通信接口
通信标准 | 引脚说明 | 通信方式 | 通信方向 |
---|---|---|---|
UART(通用异步收发器) | TXD:发送端;RXD:接受端;GND:公共地 | 异步通信 | 全双工 |
单总线(1-wire) | DQ:发送/接受端 | 异步通信 | 半双工 |
SPI | SCK:同步时钟;MISO:主机输入,从机输出;MOSI:主机输出,从机输入 | 同步通信 | 全双工 |
IIC | SCL:同步时钟;SDA:数据输入/输出端 | 同步通信 | 半双工 |
2.1、STM32的串口通信接口
UART:通用异步收发器;
USART:通用同步异步收发器;
2.2、UART异步通信方式引脚连接方法:
-RXD:数据输入引脚。数据接收。
-TXD:数据发送引脚。数据发送。
2.3、UART异步通信方式特点:
- 全双工异步通信。
- 分数波特率发生器系统,提供精确的波特率。
-发送和接受共用的可编程波特率,最高可达4.5Mbits/s - 可编程的数据字长度(8位或者9位);
- 可配置的停止位(支持1或者2位停止位);
- 可配置的使用DMA多缓冲器通信。
- 单独的发送器和接收器使能位。
- 检测标志:① 接受缓冲器 ②发送缓冲器空 ③传输结束标志
- 多个带标志的中断源。触发中断。
- 其他:校验控制,四个错误检测标志。
3.STM32串口异步通信需要定义的参数
- 起始位
- 数据位(8位或者9位)
- 奇偶校验位(第9位)
- 停止位(1,15,2位)
- 波特率设置
USART框图
二、程序编写
1.编写步骤
1.串口时钟使能,GPIO时钟使能:RCC_APB2PeriphClockCmd();
2.串口复位:USART_DeInit(); 这一步不是必须的
3.GPIO端口模式设置:GPIO_Init(); 模式设置为GPIO_Mode_AF_PP
4. 串口参数初始化:USART_Init();
5.开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)
NVIC_Init();
== USART_ITConfig();==
6.使能串口:USART_Cmd();
7.编写中断处理函数:USARTx_IRQHandler();
8.串口数据收发:
void USART_SendData();//发送数据到串口,DR
uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据
9.串口传输状态获取:
FlagStatus USART_GetFlagStatus
(USART_TypeDef* USARTx, uint16_t USART_FLAG);
void USART_ClearITPendingBit
(USART_TypeDef* USARTx, uint16_t USART_IT);
2.程序实例
代码如下(所示):
#include "stm32f10x.h"
void Bitter_USART_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能GPIOA
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能串口一
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
USART_InitStruct.USART_BaudRate=115200;//波特率
USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流控制
USART_InitStruct.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;//发送和接收
USART_InitStruct.USART_Parity=USART_Parity_No;//奇偶校验
USART_InitStruct.USART_StopBits=USART_StopBits_1;//停止位
USART_InitStruct.USART_WordLength=USART_WordLength_8b;//字长
USART_Init(USART1,&USART_InitStruct);//串口初始化
USART_Cmd(USART1,ENABLE);//串口使能函数
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开启中断服务函数;接收中断
NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn;//中断通道
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;//开启中断通道
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;//设置抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;//子优先级
NVIC_Init(&NVIC_InitStruct);
}
void USART1_IRQHandler(void)
{
u8 tea;
if(USART_GetITStatus(USART1,USART_IT_RXNE))//判断中断类型
{
tea=USART_ReceiveData(USART1);//读取串口一接收到的数据;
USART_SendData(USART1,tea);//发送数据
}
}
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级,两位抢占优先级,两位响应优先级
Bitter_USART_Init();
while(1);
}
三、…\OBJ\Project.axf: Error: L6200E: Symbol USART1_IRQHandler multiply defined (by usart.o and main.o).错误解决方法
在usart.c中找到和USART1_IRQHandler一样的函数,注释掉就可以了。
总结
编写串口还可以使用 HAL 库实现串口配置和使用的方法。。在 HAL 库中,串口相关的函数和定义主要在文件 stm32f1xx_hal_uart.c 和 stm32f1xx_hal_uart.h 中。