day6:STM32MP157——串口通信实验

使用的是cortex A7内核

【串口通信的工作原理】

本次实验使用的是uart4的串口,分别使用了uart4_tx和uart4_rx两个引脚。根据板子的原理图我们可以知道,他们分别对应着芯片的PG11和PB2

从引脚名字也可以知道使用了GPIO口,所以本次实验同样需要使用到GPIO模块。再加上uart模块和RCC使能模块。所以本次实验一共需要使用到三个模块。基本工作框图如下:

【RCC使能】

通过芯片手册可以知道RCC对GPIO使能使用的是AHB总线,对UART使能是通过APB1总线

再在芯片手册中直接查询这两个总线的寄存器即可知道需要对哪一位数据进行修改进行使能

具体使能操作情况如下

    //使能GPIOB,GPIOG,UART4RCC->MP_AHB4ENSETR |= (0x1 << 1);RCC->MP_AHB4ENSETR |= (0x1 << 6);RCC->MP_APB1ENSETR |= (0x1 << 16);

【GPIO功能复用】

通过查询芯片手册可知,只需要对GPIO的AFRL或者AFRH寄存器进行修改即可。

端口复用寄存器存在两个的原因:

对端口的复用需要4位,而每个寄存器只有32位,所以每个端口复用寄存器只能操作8个GPIO口。但是每个口都有16个,所以需要两个端口复用寄存器来分别控制低8位口和高8位口,AFRL就操作0-7这8个,AFRH就操作8-15这8个口

所以本次使用的两个口PB2和PG11分别要修改的寄存器为GPIOB_AFRL和AFRHG_AFRH寄存器,再根据寄存器的结构便可以知道要修改的是哪几位。

现在我们知道了需要设置哪几位,但是设置成什么数字并不知道,继续查询芯片手册,我们需要把它复用成uart4的模式。

从上面这两张表就可以知道,只需要把PG11对应的几位设置成AF6,把PB2对应的几位设置成AF8即可,至此GPIO口的uart4复用功能就实现了。

【UART模块设置】

对uart模块的设置相对繁琐,具体分为以下几步:

1、设置数据长度为8

2、设置16位过采样

3、设置不需要校验位

4、设置1位停止位

5、设置不分频

6、设置波特率

7、对发送器、接收器、串口分别进行使能

对上面三张图的寄存器的对应位进行修改即可实现上述七个步骤。

值得一提的是在对BRR进行波特率设置的时候可以通过直接赋值的方式直接设置波特率,但是这个需要设置的值收到过采样频率的影响,由于8倍的过采样频率过于复杂,本次实验采用16倍采样频率,具体公式如下:

设置值 = 模块工作频率(HZ)/ 要设置的波特率(bit/s)

对uart模块进行读写操作的步骤

1、判断是否有数据需要读取或写入(对USART_ISR寄存器相应的位进行判断)

2、将需要读取的数据放入读取寄存器中(数据会存储在USART_RDR寄存器等待用户读取)

3、将需要发送的数据放入写寄存器中(将数据直接写入USART_TDR寄存器即可发送数据)

【代码】

在了解了以上串口工作原理之后就可以开始编写代码了。本次代码结合了昨天的led模块,实现了串口对灯的控制。具体功能见视频:

https://blink.csdn.net/details/1666295?spm=1001.2014.3001.5501

具体代码如下:

main.c

#include "uart4.h"#include "led.h"void delay(int ms){int i,j;for(i=ms;i>0;i--){for(j=2000;j>0;j--){}}}int main(){uart4_init();led_init();// char i;char buf[30];while(1){// i = getchar();// putchar(i + 1);gets(buf);if(strcmp(buf,"led1 on")==0){led1_on();puts("exec success\r\n");}else if(strcmp(buf,"led1 off")==0){led1_off();puts("exec success\r\n");}else if (strcmp(buf, "led2 on") == 0){led2_on();puts("exec success\r\n");}else if (strcmp(buf, "led2 off") == 0){led2_off();puts("exec success\r\n");}else if (strcmp(buf, "led3 on") == 0){led3_on();puts("exec success\r\n");}else if (strcmp(buf, "led3 off") == 0){led3_off();puts("exec success\r\n");}else{puts("error cmd\r\n");}}return 0;}

uart4.c

#include "uart4.h"void uart4_init()
{//使能GPIOB,GPIOG,UART4RCC->MP_AHB4ENSETR |= (0x1 << 1);RCC->MP_AHB4ENSETR |= (0x1 << 6);RCC->MP_APB1ENSETR |= (0x1 << 16);//设置pb2和pg11的管脚复用pb2/pg11GPIOB->MODER &= ~(0x3 << 4);GPIOG->MODER &= ~(0x3 << 22);GPIOB->MODER |= (0x1 << 5);GPIOG->MODER |= (0x3 << 23);GPIOB->AFRL &= ~(0xf << 8);GPIOB->AFRL |= (0x1 << 11);GPIOG->AFRH &= ~(0xf << 12);GPIOG->AFRH |= (0x3 << 13);//设置串口不使能,ue=0USART4->CR1 &= (~(0x1));//设置8位数据位USART4->CR1 &= (~(0x1 << 12));USART4->CR1 &= (~(0x1 << 28));//设置没有奇偶校验位USART4->CR1 &= (~(0x1 << 10));//设置1位停止位USART4->CR2 &= (~(0x3 << 12));//设置16倍过采样USART4->CR1 &= (~(0x1 << 15));//设置时钟不分频USART4->PRESC &= (~(0xf));//设置波特率为115200USART4->BRR = 0x22b;//使能发送器USART4->CR1 |= (0x1 << 3);//使能接收器USART4->CR1 |= (0x1 << 2);//使能uart4USART4->CR1 |= (0x1);
}void putchar(char a)
{//先判断发送寄存器是否为空while(!(USART4->ISR & 0x1<<7)); //取出第七位的数据,如果是1表示 当前寄存器为空USART4->TDR = a;//不为空阻塞等待//为空向寄存器中写入数据//写入完成判断发送是否完成,未完成阻塞,完成函数结束while (!(USART4->ISR & 0x1 << 6));
}char getchar()
{//判断接收寄存器中是否有数据有数据读取,没数据阻塞//读取成功返回该字符char a;while (!(USART4->ISR & 0x1 << 5));a = USART4->RDR;return a;
}void puts(char *s)
{while(*s){putchar(*s);s++;}putchar('\r');putchar('\n');
}void gets(char *s)
{while(1){*s = getchar();putchar(*s);if (*s == '\r'){break;}s++;}*s = '\0';
}int strcmp(char *src,char *dest)
{char *p = src, *q = dest;while(*p==*q&&*p!='\0'&&*q!='\0'){p++;q++;}if(*p>*q){return 1;}else if(*p<*q){return -1;}else {return 0;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/768761.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

array go 语言的数组 /切片

内存地址通过& package mainimport "fmt"func main() {var arr [2][3]int16fmt.Println(arr)fmt.Printf("arr的地址是: %p \n", &arr)fmt.Printf("arr[0]的地址是 %p \n", &arr[0])fmt.Printf("arr[0][0]的地址是 %p \n"…

动态规划Dynamic Programming

上篇文章我们简单入门了动态规划&#xff08;一般都是简单的上楼梯&#xff0c;分析数据等问题&#xff09;点我跳转&#xff0c;今天给大家带来的是路径问题&#xff0c;相对于上一篇在一维中摸爬滚打&#xff0c;这次就要上升到二维解决问题&#xff0c;但都用的是动态规划思…

手机termux上用hydra在线暴力穷举破解

HYDRA 是一个在线暴力破解工具&#xff0c;速度快&#xff0c;穷举稳定&#xff0c;支持50线程的暴力穷举破解&#xff0c;兼容的协议也多&#xff0c;telnet, ftp, http, https, smb, 多数网页服务的databases&#xff0c;应用广泛。 在手机termux上也可以轻松实现。 不废话…

开源博客项目Blog .NET Core源码学习(10:App.Framwork项目结构分析)

开源博客项目Blog的解决方案总共包括4个项目&#xff0c;其中App.Hosting项目包括所有的页面及控制器类&#xff0c;其它项目主要提供数据库访问、基础类型定义等。这四个项目的依赖关系如下图所示&#xff0c;本文主要分析App.Framwork项目的主要结构及主要文件的用途。   …

水瓶座性格分析及星座配对!

水瓶座性格分析及星座配对&#xff01; 标签&#xff1a;水瓶座 水&#xff0f;瓶&#xff0f;座 1.20~2.18 “珍爱生命&#xff0c;远离水瓶” 这是一个被水瓶座折磨的巨蟹文艺男青年的呐喊 “都是外星人&#xff0c;根本没法沟通” 这是号称水瓶最佳基友的逆生长射手妹子…

21.同步模式-保护性暂停

1.Guarded Suspension,用在一个线程等待另一个线程的执行结果。 2.一个结果从一个线程传递到另一个线程&#xff0c;让他们关联同一个GuardedObject 保护对象。 3.如果有结果不断从一个线程到另一个线程&#xff0c;那么可以使用消息队列。 4.join方法和Future的实现&#x…

JavaScript原型、原型对象、原型链系列详解(三)

(三)、JavaScript原型链 原型链 在 JavaScript 中&#xff0c;对象之间的继承是通过原型链来实现的。每个对象都有一个指向原型对象的内部链接&#xff0c;也就是 [[Prototype]] 属性。这个链接的作用是如果对象本身没有某个属性或方法&#xff0c;就会去它的原型对象上找&…

Linux 进程通信:匿名管道、实现进程池

目录 一、进程间通信 1、 为什么需要进程通信 2、发展和分类 二、管道 1、概念 2、特点 2、复制并共享 3、用fork来共享管道原理 4、站在文件描述符角度-深度理解管道 5、站在内核角度-管道本质 三、匿名管道 1、概念 2、创建 3、snprintf 4、父子进程中进行单…

小程序英文口语发音评测

一、英文口语评测需求 在全球化的今天&#xff0c;英语已经成为了世界上最重要的国际语言之一。无论是在国际商务、科技研究、教育还是日常生活中&#xff0c;英语都扮演着举足轻重的角色。因此&#xff0c;掌握英文口语的能力对于个人的职业发展、学术研究以及跨文化交流都具…

【Linux】vim配置及安装方法

注 安装方法在文章最后 配置文件的位置 在目录 /etc/ 下面&#xff0c;有个名为vimrc的文件&#xff0c;这是系统中公共的vim配置文件&#xff0c;对所有用户都有效。而在每个用户的主目录下&#xff0c;都可以自己建立私有的配置文件&#xff0c;命名为“.vimrc”。例如&…

atoi函数详解

atoi函数使用方法 在c官网中是这样介绍atoi函数的 通俗的讲就是把字符串中的字符数字转换为整形数字&#xff0c;遇到空格就跳过&#xff0c;如果在字符串开始遇到不是有效的整数比如说abc就直接返回0&#xff0c;如果遇到像这种情况123abc345这个就只返回123&#xff0c;这个…

C语言数据结构之计数排序

世中逢尔 雨中逢花 目录 计数排序的介绍 代码展示 时间复杂度和空间父复杂度 计数排序的用途 计数排序的局限性 计数排序的介绍 排序原理 计数排序又称为鸽巢原理&#xff0c;是对哈希直接定址法的变形应用。 是一个不比较排序算法&#xff0c;通过计数将时间复杂度降到了O…

大型网站集群管理负载均衡

课程介绍 结合企业大规模应用&#xff0c;解决应用高并发问题&#xff0c;解决单节点故障问题&#xff0c;缓存数据库的应用。学完掌握知识点&#xff1a;企业应用实现四七层负载均衡&#xff0c;以及Nginx等应用的高可用性&#xff0c;Redis缓存数据库的部署应用以及高可用方…

【Redis】优惠券秒杀

全局唯一ID 全局唯一ID生成策略&#xff1a; UUIDRedis自增snowflake算法数据库自增 Redis自增ID策略&#xff1a;每天一个key&#xff0c;方便统计订单量ID构造是 时间戳 计数器 Component public class RedisIdWorker {// 2024的第一时刻private static final long BEGIN…

Unity 背包系统中拖拽物体到指定位置或互换位置效果的实现

在Unity中&#xff0c;背包系统是一种常见的游戏系统&#xff0c;可以用于管理和展示玩家所持有的物品、道具或装备。 其中的拖拽功能非常有意思&#xff0c;具体功能就是玩家可以通过拖拽物品图标来移动物品在背包中的位置&#xff0c;或者将物品拖拽到其他位置或界面中&…

29双体系Java学习之编程的基本过程和类的通用格式

编程的基本过程 类的通用格式 ★小贴士 类的设计应遵循单一职责原则&#xff08;SRP&#xff09;&#xff0c;即只能让一个类有且仅有一个职责&#xff0c;以保证修改的可能性尽量少。

DEll R440 LC下的硬件日志收集步骤(注意:此方法收集的日志里无操作系统的日志);

一&#xff0c; LC下的硬件日志收集步骤&#xff08;注意&#xff1a;此方法收集的日志里无操作系统的日志&#xff09;&#xff1b; 开机看到屏幕左上角出现F10的提示的时候&#xff0c;敲击F10&#xff0c;进入LC的界面&#xff1a; 找到U盘的类似文件&#xff0c;就是最终生…

无人驾驶中的坐标转换

无人驾驶中的坐标转换 无人车上拥有各种各样的传感器&#xff0c;每个传感器的安装位置和角度又不尽相同。对于传感器的提供商&#xff0c;开始并不知道传感器会以什么角度&#xff0c;安装在什么位置&#xff0c;因此只能根据传感器自身建立坐标系。无人驾驶系统是一个多传感器…

Windows/Linux-openEuler系统使用路由侠内网穿透,部署项目详细教程

文章目录 Windows/Linux-openEuler系统使用路由侠内网穿透&#xff0c;部署项目详细教程一、在windows系统下载安装路由侠并实现项目部署1、下载路由侠并注册安装到Windows系统2、点击内网映射&#xff0c;添加映射&#xff0c;注册域名前缀3、选择网站应用4、配置你想要代理项…

ubuntu上一款好用的串口工具screen

看名字&#xff0c;你猜他是什么&#xff1f; 安装 sudo apt install screen 然后将USB串口接到虚拟机&#xff0c;执行dmesg命令查看串口设备名&#xff1a; 测试&#xff1a; sudo screen /dev/ttyUSB0 115200确实很简单。