700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 基于STM32F103C8的USART串口通讯程序

基于STM32F103C8的USART串口通讯程序

时间:2024-02-09 08:48:03

相关推荐

基于STM32F103C8的USART串口通讯程序

目录

一.串口协议和RS-232、485标准,RS232、485电平、与TTL电平的区别,"USB/TTL转232"模块的工作原理(以CH340芯片模块为例)一.串口协议STMSTM32串口通信基础二.RS-232、485标准1.RS-232标准2.RS-485标准三.RS232、485电平、与TTL电平四."USB/TTL转232"模块的工作原理(以CH340芯片模块为例)二.STM32串口通信,发送hello windows(一)问题描述(二)用寄存器方式实现(三)使用HAL库编写hello windows三.总结四.参考连接

一.串口协议和RS-232、485标准,RS232、485电平、与TTL电平的区别,"USB/TTL转232"模块的工作原理(以CH340芯片模块为例)

一.串口协议

串口通信指串口按位(bit)发送和接收字节。尽管比特字节(byte)的串行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。串口通信协议是指规定了数据包的内容,内容包含了起始位、主体数据、校验位及停止位,双方需要约定一致的数据包格式才能正常收发数据的有关规范。在串口通信中,常用的协议包括RS-232、RS-422和RS-485。

设备之间的通信方式一般分为串行通信和并行通信

按照通信方式分为:同步通信和异步通信

按照数据的传输方向串口通信分为:单工、半双工、全双工

STMSTM32串口通信基础

STM32的串口通信接口有两种,分别是:UART(通用异步收发器)、USART(通用同步异步收发器)。

对于大容量STM32F10x系列芯片,分别有3个USART和2个UART。

1.UART引脚连接方法

RXD:数据输入引脚,数据接受;

TXD:数据发送引脚,数据发送。

对于两个芯片之间的连接,两个芯片GND共地,同时TXD和RXD交叉连接。这里的交叉连接的意思就是,芯片1的RxD连接芯片2的TXD,芯片2的RXD连接芯片1的TXD。这样,两个芯片之间就可以进行TTL电平通信了。

2.USART

通用同步异步收发器(Universal Synchronous Asynchronous Receiver and Transmitter)是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。有别于 USART 还有一个UART(Universal Asynchronous Receiver and Transmitter),它是在 USART 基础上裁剪掉了同步通信功能,只有异步通信。简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是 UART。串行通信一般是以帧格式传输数据,即是一帧一帧的传输,每帧包含有起始信号、数据信息、停止信息,可能还有校验信息。USART 就是对这些传输参数有具体规定,当然也不是只有唯一一个参数值,很多参数值都可以自定义设置,只是增强它的兼容性。

二.RS-232、485标准

1.RS-232标准

简介

RS-232-C是美国电子工业协会EIA(Electronic Industry Association)制定的一种串行物理接口标准。RS(Recommended Standard)是英文“推荐标准”的缩写,232为标识号,C表示修改次数。RS-232-C总线标准设有25条信号线,包括一个主通道和一个辅助通道。

RS-232-C标准规定,驱动器允许有2500pF的电容负载,通信距离将受此电容限制。例如,采用150pF/m的通信电缆时,最大通信距离为15m;若每米电缆的电容量减小,通信距离可以增加。传输距离短的另一原因是RS-232属单端信号传送,存在共地噪声和不能抑制共模干扰等问题,因此一般用于20m以内的通信。电气特性

在TxD和RxD上:

逻辑“1”:-3V~-15V

逻辑“0”:+3~+15VRS232为全双工的通信方式,一般的连接方式都为TTL电平、RS232电平,线路空闲时发送和接收的TTL电平都是高电平,电平转换芯片之后得到的RS232电平总是低。

2.RS-485标准

1.简介

RS-485又名TIA-485-A, ANSI/TIA/EIA-485或TIA/EIA-485。

RS485是一个定义平衡数字多点系统中的驱动器和接收器的电气特性的标准,该标准由电信行业协会和电子工业联盟定义。使用该标准的数字通信网络能在远距离条件下以及电子噪声大的环境下有效传输信号。RS-485使得连接本地网络以及多支路通信链路的配置成为可能。

RS485有两线制和四线制两种接线,四线制只能实现点对点的通信方式,现很少采用,多采用的是两线制接线方式,这种接线方式为总线式拓扑结构,在同一总线上最多可以挂接32个节点。

在RS485通信网络中一般采用的是主从通信方式,即一个主机带多个从机。很多情况下,连接RS-485通信链路时只是简单地用一对双绞线将各个接口的“A”、“B”端连接起来,而忽略了信号地的连接,这种连接方法在许多场合是能正常工作的,但却埋下了很大的隐患,原因1是共模干扰:RS-485接口采用差分方式传输信号方式,并不需要相对于某个参照点来检测信号,系统只需检测两线之间的电位差就可以了,但容易忽视了收发器有一定的共模电压范围,RS-485收发器共模电压范围为-7到+12V,只有满足上述条件,整个网络才能正常工作;当网络线路中共模电压超出此范围时就会影响通信的稳定可靠,甚至损坏接口;原因二是EMI的问题:发送驱动器输出信号中的共模部分需要一个返回通路,如没有一个低阻的返回通道(信号地),就会以辐射的形式返回源端,整个总线就会像一个巨大的天线向外辐射电磁波。

三.RS232、485电平、与TTL电平

RS232 RS485 TTL同属于异步串行通信,这三种通信方式本质上是电平逻辑的区别。

Rs232的电平:+15/+13 V表示“0”,-15/-13表示“1”。

RS485电平:-2V~-6V表示“0”,+2V~+6V表示“1”

TTL电平:+5V表示“1”,0V表示“0”。

四."USB/TTL转232"模块的工作原理(以CH340芯片模块为例)

1.CH340模块原理图

CH340G_VCC:模块供电点

VCC+5V:从USB取出来的5V电源

VCC+3V3:模块稳压出来的3V3电源(3.0V-3.6V)

(短路VCC+5V到CH340G_VCC:CH340G供电为5V,TTL电平为5V)

(短路VCC+3V3到CH340G_VCC:CH340G供电为3V3,TTL电平为3V3)

CH340G_TXD:串行数据输出

CH340G_RXD:串行数据输入

GND:模块接地(与目标系统地相连)

usb转串口ch340下载电路

我们通过RTS#和DTR#两个输出信号来控制STM32IC的BOOT0和BOOT1两引脚来选择启动模式,如下表:

二.STM32串口通信,发送hello windows

(一)问题描述

完成一个STM32的USART串口通讯程序(查询方式即可,暂不要求采用中断方式),要求:

1)设置波特率为115200,1位停止位,无校验位;

2)STM32系统给上位机(win10)连续发送“hello windows!”。win10采用“串口助手”工具接收。

线路连接

GND-G

3V3-3.3

RXD-A9

TXD-A10

(二)用寄存器方式实现

创建工程

当出现下列窗口直接关闭

2.编写汇编代码

;RCC寄存器地址映像 RCC_BASE EQU 0x40021000 RCC_CR EQU (RCC_BASE + 0x00) RCC_CFGR EQU (RCC_BASE + 0x04) RCC_CIR EQU (RCC_BASE + 0x08) RCC_APB2RSTR EQU (RCC_BASE + 0x0C) RCC_APB1RSTR EQU (RCC_BASE + 0x10) RCC_AHBENREQU (RCC_BASE + 0x14) RCC_APB2ENR EQU (RCC_BASE + 0x18) RCC_APB1ENR EQU (RCC_BASE + 0x1C) RCC_BDCR EQU (RCC_BASE + 0x20) RCC_CSR EQU (RCC_BASE + 0x24) ;AFIO寄存器地址映像 AFIO_BASE EQU 0x40010000 AFIO_EVCR EQU (AFIO_BASE + 0x00) AFIO_MAPR EQU (AFIO_BASE + 0x04) AFIO_EXTICR1 EQU (AFIO_BASE + 0x08) AFIO_EXTICR2 EQU (AFIO_BASE + 0x0C) AFIO_EXTICR3 EQU (AFIO_BASE + 0x10) AFIO_EXTICR4 EQU (AFIO_BASE + 0x14) ;GPIOA寄存器地址映像 GPIOA_BASEEQU 0x40010800 GPIOA_CRL EQU (GPIOA_BASE + 0x00) GPIOA_CRH EQU (GPIOA_BASE + 0x04) GPIOA_IDR EQU (GPIOA_BASE + 0x08) GPIOA_ODR EQU (GPIOA_BASE + 0x0C) GPIOA_BSRREQU (GPIOA_BASE + 0x10) GPIOA_BRR EQU (GPIOA_BASE + 0x14) GPIOA_LCKREQU (GPIOA_BASE + 0x18) ;GPIO C口控制 GPIOC_BASEEQU 0x40011000 GPIOC_CRL EQU (GPIOC_BASE + 0x00) GPIOC_CRH EQU (GPIOC_BASE + 0x04) GPIOC_IDR EQU (GPIOC_BASE + 0x08) GPIOC_ODR EQU (GPIOC_BASE + 0x0C) GPIOC_BSRREQU (GPIOC_BASE + 0x10) GPIOC_BRR EQU (GPIOC_BASE + 0x14) GPIOC_LCKREQU (GPIOC_BASE + 0x18) ;串口1控制 USART1_BASE EQU 0x40013800 USART1_SR EQU (USART1_BASE + 0x00) USART1_DR EQU (USART1_BASE + 0x04) USART1_BRREQU (USART1_BASE + 0x08) USART1_CR1EQU (USART1_BASE + 0x0c) USART1_CR2EQU (USART1_BASE + 0x10) USART1_CR3EQU (USART1_BASE + 0x14) USART1_GTPR EQU (USART1_BASE + 0x18) ;NVIC寄存器地址NVIC_BASE EQU 0xE000E000 NVIC_SETENEQU (NVIC_BASE + 0x0010);SETENA寄存器阵列的起始地址 NVIC_IRQPRI EQU (NVIC_BASE + 0x0400);中断优先级寄存器阵列的起始地址 NVIC_VECTTBL EQU (NVIC_BASE + 0x0D08);向量表偏移寄存器的地址NVIC_AIRCREQU (NVIC_BASE + 0x0D0C);应用程序中断及复位控制寄存器的地址 SETENA0 EQU 0xE000E100 SETENA1 EQU 0xE000E104 ;SysTick寄存器地址 SysTick_BASE EQU 0xE000E010 SYSTICKCSREQU (SysTick_BASE + 0x00) SYSTICKRVREQU (SysTick_BASE + 0x04) ;FLASH缓冲寄存器地址映像FLASH_ACR EQU 0x40022000 ;SCB_BASE EQU (SCS_BASE + 0x0D00) MSP_TOP EQU 0x20005000;主堆栈起始值PSP_TOP EQU 0x20004E00;进程堆栈起始值 BitAlias_BASE EQU 0x22000000;位带别名区起始地址 Flag1EQU 0x20000200 b_flas EQU (BitAlias_BASE + (0x200*32) + (0*4));位地址 b_05sEQU (BitAlias_BASE + (0x200*32) + (1*4));位地址 DlyIEQU 0x20000204 DlyJEQU 0x20000208 DlyKEQU 0x2000020C SysTim EQU 0x20000210 ;常数定义 Bit0EQU 0x00000001 Bit1EQU 0x00000002 Bit2EQU 0x00000004 Bit3EQU 0x00000008 Bit4EQU 0x00000010 Bit5EQU 0x00000020 Bit6EQU 0x00000040 Bit7EQU 0x00000080 Bit8EQU 0x00000100 Bit9EQU 0x00000200 Bit10EQU 0x00000400 Bit11EQU 0x00000800 Bit12EQU 0x00001000 Bit13EQU 0x00002000 Bit14EQU 0x00004000 Bit15EQU 0x00008000 Bit16EQU 0x00010000 Bit17EQU 0x00020000 Bit18EQU 0x00040000 Bit19EQU 0x00080000 Bit20EQU 0x00100000 Bit21EQU 0x00200000 Bit22EQU 0x00400000 Bit23EQU 0x00800000 Bit24EQU 0x01000000 Bit25EQU 0x02000000 Bit26EQU 0x04000000 Bit27EQU 0x08000000 Bit28EQU 0x10000000 Bit29EQU 0x20000000 Bit30EQU 0x40000000 Bit31EQU 0x80000000 ;向量表 AREA RESET, DATA, READONLY DCD MSP_TOP ;初始化主堆栈 DCD Start ;复位向量 DCD NMI_Handler ;NMI Handler DCD HardFault_Handler ;Hard Fault Handler DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD SysTick_Handler ;SysTick Handler SPACE 20 ;预留空间20字节 ;代码段 AREA |.text|, CODE, READONLY ;主程序开始 ENTRY ;指示程序从这里开始执行 Start ;时钟系统设置 ldr r0, =RCC_CR ldr r1, [r0] orr r1, #Bit16 str r1, [r0] ;开启外部晶振使能 ;启动外部8M晶振 ClkOk ldr r1, [r0] ands r1, #Bit17 beq ClkOk ;等待外部晶振就绪 ldr r1,[r0] orr r1,#Bit17 str r1,[r0] ;FLASH缓冲器 ldr r0, =FLASH_ACR mov r1, #0x00000032 str r1, [r0] ;设置PLL锁相环倍率为7,HSE输入不分频 ldr r0, =RCC_CFGR ldr r1, [r0] orr r1, #(Bit18 :OR: Bit19 :OR: Bit20 :OR: Bit16 :OR: Bit14) orr r1, #Bit10 str r1, [r0] ;启动PLL锁相环 ldr r0, =RCC_CR ldr r1, [r0] orr r1, #Bit24 str r1, [r0] PllOk ldr r1, [r0] ands r1, #Bit25 beq PllOk ;选择PLL时钟作为系统时钟 ldr r0, =RCC_CFGR ldr r1, [r0] orr r1, #(Bit18 :OR: Bit19 :OR: Bit20 :OR: Bit16 :OR: Bit14) orr r1, #Bit10 orr r1, #Bit1 str r1, [r0] ;其它RCC相关设置 ldr r0, =RCC_APB2ENR mov r1, #(Bit14 :OR: Bit4 :OR: Bit2) str r1, [r0];IO端口设置 ldr r0, =GPIOC_CRL ldr r1, [r0] orr r1, #(Bit28 :OR: Bit29);PC.7输出模式,最大速度50MHz and r1, #(~Bit30 & ~Bit31) ;PC.7通用推挽输出模式 str r1, [r0] ;PA9串口0发射脚 ldr r0, =GPIOA_CRH ldr r1, [r0] orr r1, #(Bit4 :OR: Bit5);PA.9输出模式,最大速度50MHz orr r1, #Bit7 and r1, #~Bit6 ;10:复用功能推挽输出模式 str r1, [r0] ldr r0, =USART1_BRR mov r1, #0x271 str r1, [r0] ;配置波特率-> 115200 ldr r0, =USART1_CR1 mov r1, #0x200c str r1, [r0] ;USART模块总使能 发送与接收使能 ;71 02 00 00 2c 20 00 00 ;AFIO 参数设置 ;Systick 参数设置 ldr r0, =SYSTICKRVR ;Systick装初值 mov r1, #9000 str r1, [r0] ldr r0, =SYSTICKCSR ;设定,启动Systick mov r1, #0x03 str r1, [r0] ;NVIC ;ldr r0, =SETENA0 ;mov r1, 0x00800000 ;str r1, [r0] ;ldr r0, =SETENA1 ;mov r1, #0x00000100 ;str r1, [r0] ;切换成用户级线程序模式 ldr r0, =PSP_TOP ;初始化线程堆栈 msr psp, r0 mov r0, #3 msr control, r0 ;初始化SRAM寄存器 mov r1, #0 ldr r0, =Flag1 str r1, [r0] ldr r0, =DlyI str r1, [r0] ldr r0, =DlyJ str r1, [r0] ldr r0, =DlyK str r1, [r0] ldr r0, =SysTim str r1, [r0] ;主循环 main ldr r0, =Flag1 ldr r1, [r0] tst r1, #Bit1 ;SysTick产生0.5s,置位bit 1 beq main ;0.5s标志还没有置位 ;0.5s标志已经置位 ldr r0, =b_05s;位带操作清零0.5s标志 mov r1, #0 str r1, [r0] blLedFlas mov r0, #'H' blsend_a_charmov r0, #'e' blsend_a_charmov r0, #'l' blsend_a_charmov r0, #'l' blsend_a_charmov r0, #'o' blsend_a_charmov r0, #' ' blsend_a_charmov r0, #'w' blsend_a_charmov r0, #'i' blsend_a_charmov r0, #'n' blsend_a_charmov r0, #'d' blsend_a_charmov r0, #'o' blsend_a_charmov r0, #'w' blsend_a_charmov r0, #'s' blsend_a_charmov r0, #'!' blsend_a_charmov r0, #'\n' blsend_a_charbmain;子程序 串口1发送一个字符 send_a_char push {r0 - r3} ldr r2, =USART1_DR str r0, [r2] b1 ldr r2, =USART1_SR ldr r2, [r2] tst r2, #0x40 beq b1 ;发送完成(Transmission complete)等待 pop {r0 - r3} bxlr ;子程序 led闪烁 LedFlaspush {r0 - r3} ldr r0, =Flag1 ldr r1, [r0] tst r1, #Bit0 ;bit0 闪烁标志位 beq ONLED ;为0 打开led灯 ;为1 关闭led灯 ldr r0, =b_flas mov r1, #0 str r1, [r0] ;闪烁标志位置为0,下一状态为打开灯 ;PC.7输出0 ldr r0, =GPIOC_BRR ldr r1, [r0] orr r1, #Bit7 str r1, [r0] bLedEx ONLED ;为0 打开led灯 ldr r0, =b_flas mov r1, #1 str r1, [r0] ;闪烁标志位置为1,下一状态为关闭灯 ;PC.7输出1 ldr r0, =GPIOC_BSRR ldr r1, [r0] orr r1, #Bit7 str r1, [r0] LedEx pop {r0 - r3} bxlr ;异常程序 NMI_Handler bxlr HardFault_Handler bxlr SysTick_Handler ldr r0, =SysTim ldr r1, [r0] add r1, #1 str r1, [r0] cmp r1, #500 bcc TickExit mov r1, #0 str r1, [r0] ldr r0, =b_05s ;大于等于500次 清零时钟滴答计数器 设置0.5s标志位 ;位带操作置1 mov r1, #1 str r1, [r0] TickExit bxlr ALIGN ;通过用零或空指令NOP填充,来使当前位置与一个指定的边界对齐 END

3.编译、生成hex文件

编译无错误

生成hex文件详细设置参照另一文章《KEIL嵌入式环境下,基于STM32汇编程序的编写》

4.烧录

芯片BOOT0置1,BOOT1置0,打开mcuisp,选择文件路径,进行烧录:

5.串口调试

6.观察波形

设置参数:

添加要观察的引脚:

观察波形:

(三)使用HAL库编写hello windows

1.新建项目

(1)打开STMCubeMX,创建新项目:

(2)在part name里选择自己的芯片,点击信息栏中的具体芯片信息选中,点击start project:

(3)配置时钟

(4)设置USART1

(5)点击Clock Configuration选择HSE和PLLCLK

(6)选择路径等

(7)打开项目

2.编写main.c代码

在main.c中的while循环中添加代码:

char data[]="hello windows!\n";HAL_UART_Transmit(&huart1, (uint8_t *)data, 15, 0xffff);HAL_Delay(1000);

3.程序烧录

创建.hex文件

BOOT0置1,BOOT1置0,,打开mcuisp,选择文件路径,进行烧录。

4.串口调试

BOOT0置0,BOOT1置1,打开野火串口调试助手:

5.观察波形

参数设置:

编译,debug,添加要观察的引脚:

观察波形:

三.总结

采用寄存器方式写比较复杂,要声明很多地址,语句也比较繁琐;而采用HAL库只需要在主函数里写几句代码就可以实现,更方便,不易出错。

四.参考连接

/qq_46467126/article/details/120841504?spm=1001..3001.5502

/weixin_46129506/article/details/120895633

/eker_ch/article/details/21043591

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。