stm32f103的USART通信

简介

USART英文名字: Universal Synchronous/Asynehronous Receive/Transmitter.

最少需要3根线, GND, RX(接收), TX(发送). 当只需单向数据传输时, 可以只用一根通信线, 当电平标准不一致时, 需要加电平转换芯片.

全双工(发时收,收时发), 异步(不需要时钟线), 单端(必须共地), 点对点(1对1)通信.

通信协议: 制定通信的规则, 通信双方按照协议规则进行数据收发.

stm32f103的USART通信_第1张图片

串口参数

  • 波特率: 通信的速率.
  • 起始位: 标志一个数据帧的开始, 固定为低电平.
  • 数据位: 数据帧的有效载荷, 1为高电平, 0为低电平, 低位现行.
  • 校验位: 用于数据验证, 根据数据位计算得来, 奇校验, 偶校验.
  • 停止位: 用于数据帧间隔, 固定为高电平
  • 空闲状态: 为高电平

一帧数据有10/11位.

低位现行: 从最低位开始发送.

stm32f103的USART通信_第2张图片

串口常用电平标准

  • TTL电平: +3.3v或+5v为1, 0v为0.
  • RS232电平: -3v到-15v为1, +3v到+15v为0.
  • RS485电平: 差分信号, 两线压差+2到+6v为1, -2到-6v为0.

波特率和比特率的区别

波特率: 单位: 码元/s, 波特.

比特率: 每秒传输的比特数, 单位: bit/s, bps.

二进制中一个码元等于1bit, 所以波特率等于比特率, 其他进制中不同.

USART外设

USART是STM32内部集成的硬件外设, 可根据数据寄存器的一个字节数据自动生成数据帧时序, 从TX发送, RX自动接收, 并拼接为一个字节数据, 存放在数据寄存器里.

 发送/读取数据位, 是电路自动完成的, 也可以用GPIO软件模拟收发, 但是大大增加CPU负担, 这里只研究硬件电路.

stm32自带波特率发生器, 最高达4.5Mbit/s

可配置数据位长度:8/9

停止位长: 0.5/1/1.5/2

支持同步模式, 硬件流控制(多一根线, 防止发送快处理慢, 导致数据丢失, 反馈信号线, RTS,CTS), DMA(大量数据收发), 智能卡, LrDA, LIN.

输入数据采样, 在时钟中间位置, 选3个数据位, 全为1 = 1, 全为0 = 0. 如果2个1, 1个0 = 0, 但是噪声标志位EA = 1.

接收数据两种方式 

  1.  查询: 不用配置中断, 在主循环中不断查询RXNE寄存器, 浪费资源还容易反应迟钝.
  2. 中断: RXNE中断

说明很多外设都可以不中断使用查询标志位方式, 但紧急处理还是要使用中断.

程序逻辑

  1.  RCC使能GPIO, USART
  2. GPIO初始化, TX复用输出, RX上拉/浮空输入
  3. USART初始化
  4. *中断配置ITConfig
  5. *配置NVIC
  6. 开启USART

如果只要发, 不用接收, 不用配置带星号的. 

参考代码

 头文件

#ifndef __USART_H

#include "stm32f10x.h"                  // Device header
#include
#include


#define GPIO_TX  GPIO_Pin_9
#define GPIO_RX  GPIO_Pin_10

extern uint16_t receiveData;//接收数据
extern uint16_t receiveFlag;//接收标志

void USART_Config(void);//USART配置
void sendByte(uint16_t Data);//发送1字节
void sendNum(uint32_t num);//发送数字
void sendString(char * str);//发送字符串
void serialPrintf(char* format, ...);//类似printf函数

#endif

 源文件

#include "USART.h"

uint16_t receiveData = 0;
uint16_t receiveFlag = 0;

void USART_Config(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Pin = GPIO_TX;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStruct.GPIO_Pin = GPIO_RX;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    USART_InitTypeDef USART_InitStruct;
    USART_InitStruct.USART_BaudRate = 9600;
    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_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    NVIC_InitTypeDef NVIC_InitStruct;
    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);
    
    USART_Cmd(USART1, ENABLE);
}

void sendByte(uint16_t Data)
{
    USART_SendData(USART1, Data);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //等待发送完成
}

void sendString(char * str)
{
    uint16_t i = 0;
    while(str[i] != '\0')
    {
        sendByte(str[i++]);
    }
}

static uint16_t numOfDigital(uint32_t num) //输出数字的位数
{
    uint16_t sz = 0;
    while(num != 0)
    {
        num /= 10;
        sz++;
    }
    return sz;
}

static uint32_t numPow(uint32_t num, uint16_t sz)
{    
    uint32_t Result = 1;
    while (sz --)
    {
        Result *= num;
    }
    return Result;
}

void sendNum(uint32_t num)
{
    uint16_t sz = numOfDigital(num);
    for(uint16_t i = 0; i < sz; i++)
    {
        sendByte(num/numPow(10,sz-i-1)%10 + '0');
    }
}

void USART1_IRQHandler(void)
{
    if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
    {
        receiveData = USART_ReceiveData(USART1);
        receiveFlag = 1;
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除接收中断标志位
    }
}

int fputc(int ch, FILE* f)//重定向fputc,printf底层就是fputc,只有串口1能用
{
    sendByte(ch);
    return ch;
}

void serialPrintf(char* format, ...)
{
    char string[100];
    va_list arg;
    va_start(arg, format);
    vsprintf(string, format, arg);
    va_end(arg);
    
    sendString(string);
}

逻辑分析仪分析信号

 发送数据0x41波形图如下所示.

其他问题

发送中文字符不换行

在魔术棒 -> C/C++ -> Misc Controls 写入: 

--no-multibyte-chars

中文编码字节数

UTF-8: 3字节

GBK: 2字节

sprintf()

 char str[100];

sprintf(str, "hello world %d", 123); //将字符串打印到str数组中去.

你可能感兴趣的:(stm32,嵌入式硬件,单片机)