内容回顾:
阻塞和非组塞:按键控制LED2的同时LED1正常闪烁
STM32开发基础:内部总线,时钟配置,内存
GPIO:点灯,按键
问题:
代码写完不报错,但是仿真里运行没效果。
仿真原理图绘制问题,可以先用群里发的原理图做测试,然后再检查自己的原理图
代码报错:
一般是因为,函数没有声明,一个是头文件名字不对或者没有包含头文件,包含了头文件,但是还是报错,检查有没有把对应的c文件添加到工程里。
实际开发板使用过程中可以使用WIFI,仿真里没有这个原件,但是仿真中有串口,可以使用串口发送数据。
- 通信的概念以及分类
通信概念 | 通过某种行为或者某种媒介进行信息交流与传递 | ||
通信分类 | 传输媒介 | 有线通信 | USB、以太网、485、CAN等 信号稳定、传输速度较快,传输距离短 |
无线通信 | wifi、蓝牙、GSM、GPRS、4G、5G、Lora、zigbee、NBIOT、433、短波、2.4G等等 | ||
通信范围 | 广域网通信 | 通信厂商提供通信手段 -- 4G 5G NBIOT 开发布局网络容易、流量 | |
局域网通信 | 本地组网,稳定性 布线容易、传输速度较慢等 | ||
通信方式 | 单工通信 | 设备只能发送或则接收,例如:广播电视 | |
半双工通信 | 同一时刻,只能发送或者接收,例如:对讲机 | ||
全双工通信 | 同一时刻,既能发送又能接收,例如:串口,手机 | ||
收发时机 | 同步通信 | 收发数据在同一个CLK(时钟信号)下 | |
异步通信 | 收发数据不在同一个CLK(时钟信号)下 | ||
数据传输方式 | 串行通信 | 一次传输1位的数据,1根数据线,1个GPIO口 | |
并行通信 | 一次可以同时传输多位数据(传输速率更快,通信距离短) 一次16位数据,需要16根数据线,16个GPIO口 |
- 什么是串口通信?
串行通信接口:9针和25针
DB9接口不等于VGA
- 串口通信的作用
一般:调试用,更多是和其它模块进行通信
通信的媒介
- 串口通信的物理层(硬件链接)
3根线 | TxD | 数据的发送管脚 |
RxD | 数据的接收管脚 | |
GND | 共地 | |
电平标准 | TTL电平 | 1 -- 2.5V-5V、0 -- 0V-1.5V |
应用 | 芯片与芯片相连 | 通信距离短,方便 |
外设与芯片相连 | | |
手机与开发板相连 | 手机提供的接口:wifi和蓝牙 | |
电脑与开发板相连 | USB信号与串口信号的转换(通过CH340芯片实现) USB接口:数字信号0/1 根据U+和U-之间的电压差来判断 串口:0 -- 0-1.5V 1 -- 2.5-5V 上位机:电脑上的控制软件 下位机:开发板 上位机控制下位机(通过指令来控制) |
- 串口通信的协议层
串口通信协议 | RS232: 其传送距离最大为约15米,最高速率为20kb/s。RS-232是为点对点,位协议。 RS485: 总线上可多接到32个设备。 | |
RS232通信协议 | 通信格式 | 开始位+数据位+奇偶校验位+停止位 位数 1 5~8 0~1 1 电平 0 0/1 0/1 1 (1)开始位:低电平 -- 设备检测下降沿,代表开始 (2)数据位:5 -- 0000 0101 5~8位 -- 8位 (3)奇偶校验位:校验一帧数据是否完整 奇偶校验:数据位中1的个数+奇偶位中1的个数之和 如果是奇校验:个数之和必须为奇数。 如果是偶校验:个数之和必须为偶数。 例如: 发送方:0 0110 0011 1 1 --> 奇数 接收方:0110 0011 1 --- 奇数,正确 0100 0011 1 --- 偶数,错误 0000 0011 1 --- 奇数,奇偶校验正确,数据错误 现在采用CRC校验 (4)停止位:高电平 -- 总线状态空闲为高电平。 常用帧格式:1+8+0+1 -- 1个开始位+8个数据位+0个奇偶校验位+1个停止位 总线空闲状态:数据线是高电平 |
通信速率 | 波特率bps(每秒钟发送的位数),进行通信的两个设备,波特率必须一样 常见的波特率:115200,9600 |
- STM32中的串口
- STM32F103R6中集成了几个串口?两个USART
仿真中串口1数据是稳定的,串口2 数据会丢失
在连接阿里云时要保证数据准确无误,建议使用串口1作为,连接阿里云的端口
- STM32中串口的工作原理(查看参考手册)
STM32中串口的配置步骤
- STM32串口代码实现
1,确定硬件接口:具体使用那个引脚
代码流程:
- 配置IO
- 开时钟
- 配置模式
- 初始化
- 配置串口
- 开时钟
- 配模式
- 初始化
- 使能串口
//使用USART1 TX-》PA9 RX-》PA10 void Usart_Config(void) { //1,配置IO口 GPIO_InitTypeDef GPIO_InitStruct={0}; //开时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //配置模式 GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;//TX引脚 GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//速度 //初始化 GPIO_Init(GPIOA, &GPIO_InitStruct); //配置模式 GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;//浮空输入 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;//RX引脚 //初始化 GPIO_Init(GPIOA, &GPIO_InitStruct);
//2,配置串口 //初始化时钟 USART_InitTypeDef USART_InitStruct={0}; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //配置串口模式 USART_InitStruct.USART_BaudRate=57600;//波特率57600,和仿真保持一致 USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流控制失能 USART_InitStruct.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;//全双工通信,发送和接受都使能 USART_InitStruct.USART_Parity=USART_Parity_No;//不使用奇偶校验 USART_InitStruct.USART_StopBits=USART_StopBits_1;// 在帧结尾传输 1 个停止位 USART_InitStruct.USART_WordLength=USART_WordLength_8b;//8位字长
//初始化串口 USART_Init(USART1, &USART_InitStruct);
//3,使能串口 USART_Cmd(USART1, ENABLE); } //printf重定向 #include "stdio.h" int fputc(int c,FILE *stream) { while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==0){} USART_SendData(USART1,c); return c; } //串口发送一位数据 void Usart_SendByte(u8 data) { // while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==0){}//代表没有发送完成 // USART_SendData(USART1,data); while((USART1->SR &(1<<6)) == 0){} USART1->DR=data; } //发送字符串 void Usart_SendStr(u8 Str[],uint16_t len) { uint16_t i=0; for(i=0;i<len;i++) { Usart_SendByte(Str[i]); } } //接受数据 uint8_t Usart_RecvByte(void) { while((USART1->SR & (1<<5)) == 0)//如果没有数据,就卡到这里 {} return USART1->DR; } |
printf重定向:
原本的printf是将数据输出到屏幕上
在仿真里或实际开发板中使用printf,需要将printf进行重定向
自己写一个fputc函数,把数据从串口发送出去
使用printf要包含stdio.h头文件