串口发送数据,SysTick定时器的实现

一、串口发送数据

1)大概了解

c 复制代码
RX:接收
TX:发送
连接时需要交叉连接,RX连接对方的TX、TX连接对方的RX
任意的串口都至少需要连接三个引脚:RX、TX、GND
STM32F103C8上有3个串口:USART1、2、3
USART1-TX:PA9
USART1-RX:PA10
TX:复用推挽输出
RX:浮空输入
使用到了复用功能,需要开启复用时钟(AFIO)

2)代码与分析

usart.c

c 复制代码
int fputc(int ch,FILE *file)
{
    USART_SendData(USART1,ch);
    //等待发送完成
    while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
    
    return ch;
}

输出重定向:即能够在串口上显示,若没有这个函数串口不会显示任何数据 (将原本输出到标准设备的内容发送到串口)

USART_SendData(USART1,ch):将字符ch发送到 USART1串口的数据寄存器中启动发送流程。

while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET)

c 复制代码
当为RESET时表示发送缓冲区不为空,程序会一直停留在这个循环中,
直到数据已经从发送全部发送出去了,USART_FLAG_TXE会被硬件置位1循环结束,下一操作
可以理解为传送带上快递的运输,直到快递全部运输完成,传送带为空

串口引脚的初始化,一般使用推挽输出

波特率、数据位、奇偶校验位、停止位、模式化选择、硬件流控的初始化
USART_Cmd:对前面配置好的串口激活,使能串口1

c 复制代码
void send_char(char ch)
{
    USART_SendData(USART1,ch);
    //等待发送完成
    while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);//表示标志位未被置位,即发送缓冲区不为空,程序会一直停留在这个循环中
                                                             //只有当发送缓冲区为空(即数据已经从发送缓冲区发送出去了)
                                                             //USART_FLAG_TXE标志被置位,此时USART_GetFlagStatus函数返回非RESET值,循环结束
                                                             //USART_FLAG_TXE(发送数据寄存器为空标志)是由硬件自动置位的
}

跟上诉原理一致,循环遍历每一个字符
.h

main.c

c 复制代码
#include "stm32f10x.h"                  // Device header
#include "printf.h"
#include "stdio.h"

void delay_ms(int x)
{
    int i=0;
    while(x--)
        for(i=0;i<8050;i++);
}

int main()
{
    int i=0;
    printf_init(9600);
    while(1)
    {
        //Send_Char('A');
		//delay_ms(10);
        printf("i=%d\r\n",i++);
        delay_ms(10);
        printf("hello world\n");
        delay_ms(10);
    }
}

二、SysTick

1)数据手册

c 复制代码
COUNTFLAG:计数标志位
如果计时器自上次读取以来计数为0,则返回1

CLKSOURCE:时钟源设置,AHB默认72MHz
0:AHB/8
1:AHB

TICKINT:中断使能位
0:倒计时到0不产生中断
1:倒计时到0产生中断

ENABLE:SysTick使能位
0:关闭定时器
1:开启定时器


2)代码与分析

将时钟进行8分频,得到AHB/8=9MHz

SysTick->LOAD :重装载值设置为8999999(定时器在启动时会将这个值加载到内部的计数逻辑中 ),直到减位0时进行了9000000次
SysTick->VAL :让定时器从一个确定的初始状态开始计数。这里的初始状态是指定时器内部的计数逻辑部分 ,确保它在开始计数时没有受到之前可能遗留的计数值的干扰。

SysTick->CTRL &= ~(1<<1):倒计时到0时不产生中断
SysTick->CTRL |=1 :使能ENABLE,打开定时器。

一旦定时器启动,定时器的计数逻辑会从SysTick->LOAD寄存器获取初始值,也就是9000000 - 1

这个值会被加载到用于实际计数的内部寄存器(这个内部寄存器和SysTick->VAL有联系 ,但在启动时是从SysTick->LOAD加载初始值),也就是VAL从初始值处开始递减
while(SysTick->CTRL & (1<<16)==0);

c 复制代码
把SysTick->CTRL寄存器想象成一个 32 个小格子(位)组成的盒子,每个小格子可以放 0 或者 1。
(1 << 16)这个操作,就像是在一个新的 32 个小格子组成的盒子里,把一个 "1" 从最右边(第 0 位)开始,
向左移动 16 个小格子,这样就得到了一个只有第 16 个小格子是 "1",其他小格子都是 "0" 的盒子。

一开始,SysTick->CTRL这个盒子的第 16 个小格子(代表计数到 0 的信号)是 "0"
,当我们进行SysTick->CTRL & (1 << 16)操作时,得到的结果也是 "0"
就像小机器人还没收到信号,所以它会一直等在while循环里

随着 SysTick 定时器在后台默默地计数,就好像有一个隐藏的倒计时在进行。
当这个倒计时结束,也就是定时器计数到 0 的时候,硬件会把SysTick->CTRL盒子的第 16 个小格子变成 "1"
时再进行SysTick->CTRL & (1 << 16)操作,得到的结果就不是 "0" 了
程序就知道定时器已经计数到 0 了,延时完成,于是它就跳出while循环,继续后面的工作

最后再关闭定时器,形成闭环也就是1s

相关推荐
heater4042 小时前
【STM32】I2C为什么要开漏输出和上拉电阻
stm32·单片机·嵌入式硬件
沐欣工作室_lvyiyi2 小时前
数字PWM直流调速系统设计(论文+源码)
stm32·单片机·嵌入式硬件·物联网·毕业设计
逝灮6 小时前
Keil5报错:Error: L6218E: Undefined symbol __initial_sp (referred from entry2.o).
stm32·单片机·嵌入式硬件·keil5·keil5报错
黑果果的思考6 小时前
STM32 NOR FLASH(SPI FLASH)驱动移植(2)
stm32·嵌入式硬件
Asa3197 小时前
无刷直流电机偏移角度
stm32·单片机·嵌入式硬件
PegasusYu9 小时前
STM32CUBEIDE FreeRTOS操作教程(十二):std dynamic memory 标准动态内存
stm32·freertos·rtos·stm32cubeide·free-rtos·标准动态内存·dynamic memeory
aloneboyooo16 小时前
SPI通信-(STM32)
stm32·单片机·嵌入式硬件
爱学电子的刻刻帝18 小时前
STM32传感器系列:GPS定位模块
stm32·单片机·嵌入式硬件·gps
沐欣工作室_lvyiyi20 小时前
基于单片机的核辐射探测系统设计(论文+源码)
stm32·单片机·嵌入式硬件·物联网·智能家居
ElePower952721 小时前
STM32学习(四)
stm32·嵌入式硬件