当前位置: 首页 > news >正文

总线学习4--UART

想来串口通信是我第一次接触嵌入式就知道的,一直调试也是用串口线,但是里面的原理还真不清楚。这次难得把环境弄出来了,就顺便学学。

一 环境搭建

还是老规矩,废话不多说,干就完事。

这次用的树莓派zero小板,一个USB转串口。接线真的很简单,RX->TX,TX->RX,再接个地(我的实验里面地不接也行)。电脑上串口终端软件用的是mobaXterm。代码还是老朋友micropython。

二 协议分析

这次实验的目标是做一个串口echo程序。最开始是直接用GPT的代码上来怼,本来以为很简单,一个小时结束战斗。但是真跑起来根本没法用。回显的全是乱码。没办法,又拿出祖传的逻辑分析仪看看。

先还是抓几个PC出来的波形吧。波特率设置的9600。很多协议,只要看了波形,真的很好懂。

传输数字1

因为波特率是9600,那么每个信号的时间就是1/9600秒,大概就是104us。所以可以看出,这里的波形是0 1000 1100。第一个下拉0是起始位。所以数据是1000 1100。

但是1的ascii码是49,换成二进制是110001这里好像是没对啊。看了很久眼睛都看痛了,终于发现110001如果补全就是0011 0001,刚好和上面的1000 1100是反的。查了一下这个原来叫LSB first。取数据的时候倒着取就行了。

传输数字2

有了1的经验,下面就简单很多,这个波形是0 0100 1100。2的ascii是50,刚好是110010,补全之后是0011 0010,刚好也是直接反过来就行。

总结

总结一下UART协议

基本就是两根线(不算地线),甚至你都可以理解成一根线,只是方向相反而已。也没有时钟那些乱七八糟的,时隙直接sleep就欧了。数据一次一个byte,高就是1,低就是0。真的很简单。。在嵌入式里面,不知道有没有比它更简单的协议。。。

上图的校验位据说基本上不会用的。。。

三 代码实现

解决了LSB first问题,后面没有太多难点。虽然说协议真的不难,但是编程的时候还是遇到一些坑。

1 需要微秒级的定时器。

GPT给的代码是:

baudrate = 1200
bit_time = 1 / baudrateutime.sleep(bit_time)

事实上这样用根本就不准,取出来的值每次都不同。改成下面才算解决问题。

bit_time = 832
utime.sleep_us(bit_time)

2 Python的性能确实不大行

最开始设置的波特率是9600,已经算很低了,每个时隙是差不多100微妙。但是micropython软件处理这个时间好像也够呛,最后索性改成最小的波特率1200,每个时隙接近1毫秒,才算把问题解决。

3 调试

在以往上层纯软环境中,调试环境往往相对简单。直接用print或者cout都不用考虑太多。但是在底层编程中,print就会有影响了,因为print本上也是一个io操作。稍微不注意,就把程序的时间逻辑给破坏了。

    for i in range(8):if rx_pin.value():print("1")byte |= (1 << i)else:print("0")

最开始我是想这样看收到的数据,但是这个打印只要一加上,程序立马就混乱了。。。最后只有等一个byte抓完,再整体打印,这样就暂时没问题了。

做的好还是应该像Android那样,log是一个独立的系统,这样影响最小。

好了,解决完上面的问题,也就比较顺利了。

最后的结果:

最后的代码

import machine
import utime# 定义 UART 参数
bit_time = 832# 定义 GPIO 引脚
tx_pin = machine.Pin(0, machine.Pin.OUT)
rx_pin = machine.Pin(1, machine.Pin.IN)# 初始化 TX 引脚为高电平(空闲状态)
tx_pin.value(1)def uart_send_byte(byte):# 发送起始位(低电平)tx_pin.value(0)utime.sleep_us(bit_time)# 发送数据位(LSB first)for i in range(8):tx_pin.value((byte >> i) & 1)utime.sleep_us(bit_time)# 发送停止位(高电平)tx_pin.value(1)utime.sleep_us(bit_time)def uart_receive_byte():# 等待起始位(低电平)while rx_pin.value() == 1:utime.sleep_us(2)# 等待半个位时间,进入数据位的中间utime.sleep_us(832 + 416)# 接收数据位byte = 0for i in range(8):if rx_pin.value():byte |= (1 << i)utime.sleep_us(bit_time)# 等待停止位#utime.sleep_us(bit_time)return byte# UART Echo 功能实现
while True:byte = uart_receive_byte()print("Received:", chr(byte))  # 打印接收到的数据uart_send_byte(byte)           # 回显接收到的数据

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • pom.xml和.m2的setting的区别?
  • 【秋招笔试】24-07-27-OPPO-秋招笔试题(后端卷)
  • ES相关介绍与扫盲
  • 【C语言】C语言期末突击/考研--详解一维数组与字符数组
  • 罗杰斯的逆势投资:破而后立
  • 如何选择合适的气膜生产厂家—轻空间
  • 动态规划.
  • (四)软件性能测试
  • Python基于Prophet实现时间序列数据趋势周期特征提取项目实战
  • Vulnhub靶机:JANGOW_ 1.0.1
  • Java面试必看!知己知彼才能百战百胜,如何做好面试前的准备?
  • 光线追踪(纹理映射)
  • c语言-EasyX库编写的第一个项目-哪都通快递平台
  • 《Advanced RAG》-07-探索 RAG 中表格数据的处理方案
  • CSS对元素的分类
  • 9月CHINA-PUB-OPENDAY技术沙龙——IPHONE
  • 分享的文章《人生如棋》
  • 《Java编程思想》读书笔记-对象导论
  • 【剑指offer】让抽象问题具体化
  • CSS魔法堂:Absolute Positioning就这个样
  • Debian下无root权限使用Python访问Oracle
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • Docker入门(二) - Dockerfile
  • Hexo+码云+git快速搭建免费的静态Blog
  • JavaScript的使用你知道几种?(上)
  • js作用域和this的理解
  • LeetCode29.两数相除 JavaScript
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • uva 10370 Above Average
  • 测试如何在敏捷团队中工作?
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 基于阿里云移动推送的移动应用推送模式最佳实践
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 软件开发学习的5大技巧,你知道吗?
  • 学习HTTP相关知识笔记
  • 一道面试题引发的“血案”
  • 智能合约Solidity教程-事件和日志(一)
  • Linux权限管理(week1_day5)--技术流ken
  • 阿里云ACE认证之理解CDN技术
  • 如何在招聘中考核.NET架构师
  • ​TypeScript都不会用,也敢说会前端?
  • #pragma once
  • (39)STM32——FLASH闪存
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (二)Linux——Linux常用指令
  • (二十一)devops持续集成开发——使用jenkins的Docker Pipeline插件完成docker项目的pipeline流水线发布
  • (分享)自己整理的一些简单awk实用语句
  • (几何:六边形面积)编写程序,提示用户输入六边形的边长,然后显示它的面积。
  • (六) ES6 新特性 —— 迭代器(iterator)
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (算法)求1到1亿间的质数或素数
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • **PHP分步表单提交思路(分页表单提交)
  • .gitignore文件设置了忽略但不生效
  • .net core 6 集成和使用 mongodb