AVR单片机教程——第三期导语
背景(一)
寒假里做了一个灯带控制器:
理想情况下我应该在一个星期内完成这个项目,但实际上它耗费了我几乎一整个寒假,因为涉及到很多未曾尝试的方案。在这种不是很赶时间的、可以自定目标、自由发挥的项目中,我喜欢这么做。
简要介绍一下这个项目。硬件部分:
12V直流电源供电,开关降压到4V,LDO降压到3.3V,三路供电;
使用STM32G030KBT6单片机,基于Cortex-M0+;
12V灯带用异步降压驱动;
WS2812B灯带的数据用SPI信号加上一定的逻辑运算生成;
OLED屏通过I²C连接单片机;
无定位旋转编码器连接定时器的两个通道。
软件部分:
用多项式拟合把ADC读到的值转换成温度;
指令与数据调度、两级流水线式OLED更新策略;
完全自主设计的简单GUI,包括绘图与控制逻辑。
大约一半时间花在两种灯带的方案验证上,我制作了两块PCB才最终确定以上硬件方案;另有一部分时间花在STM32和HAL的调试上,但这本来就在我的STM32学习计划中;剩下的主要是OLED和GUI,以及写不出来时的摸鱼行为。
我赶在去学校当天的上午完成了项目,在砍掉一点完成度的前提下。有那么几个小时,我很后悔把整个寒假都花在了这个项目上,没有学该学的数学、写该写的博客。但是现在回想起来,这个项目让我对单片机开发有了新的认识。
背景(二)
曾经AVR单片机教程唯一的读者要开始独立做项目了,这是对我文章质量的一次考验。从我们之间的交流来看,我没有通过这次考验——
我说从供电开始思考:通常USB可以提供5V1A,如果需要5V2A,就应该考虑从12V1A转换。她问如何转换,于是我给她介绍了降压转换器。那么如何确定电流呢?主要耗电器件是32个LED。按我的思路,也可以说是绝大多数业内人士的思路,每个灯不会超过20mA,加起来640mA,其余器件耗电忽略,1A肯定是够的。而她的思路是,算出每个LED的等效电阻,并联起来,再计算电流。她又问,如果电源是5V2A,但负载只有5V1A,会烧坏吗?
然后决定用什么灯。两年半以前我送给她一个礼物,用32个LED组成一颗心,灯是红蓝交错的。她想做得比这个高级一点,用32个RGB灯,但这么多灯的连接是个问题,以及RGB三种颜色之间的亮度匹配。又想到WS2812B,它在功能上很强,但是控制稍微麻烦一点。我提示她可以用PWM来生成控制信号,她又搞不清这里的PWM和PWM呼吸灯的区别。
可能是因为在第二期里学过OLED屏和u8g2,在电赛中又用过一遍,又收到了带OLED屏的礼物,她觉得OLED屏很简单,想在项目中也放一块。
暂时不作评价,继续说事。后来又有两人从博客园后台联系我,以成本价拿到了开发板,成为了教程的读者(至此我已经没有多余的开发板了)。一位读者刚开始学C,他常常问我两类我不希望他问的问题(请这位读者不要生气):一类是与单片机无关的纯C语言问题,另一类是与教程进度不符的、我想隐藏的实现细节问题。
他们让我开始反思教程的内容是否充足、顺序编排是否合理。
回顾(一)
他们问我的这些问题,很多也是我曾经困惑的。
预初的那个暑假,我正式学习了C语言。此后,我想写一个C程序来加密文件,把若干字节作为一组处理一下,写进新的文件,就算是加密了。文件长度不一定是整组的,最后一组可能要加入几个空的字节,这种现在看来很基础的控制逻辑,我当时想了很久都写不出来。
我也长期以来不知道电池充电的电流是如何控制的,在我看来把5V电压加到3.7V锂电池上根本不可控啊!后来才知道降压、参考电流、反馈控制之类的。某些营销号还说5V2A充电器给5V1A手机充电会造成损坏,也难怪非专业人士容易受误导了。
高一的那个暑假,我完成了第一个像样的项目,就是前面提到的那颗心。32个LED分别串联470Ω排阻,接到4片级联的74HC595上,用GPIO驱动。放到现在,如果不改变设计目标,我会选择8*4动态扫描的连接方式,还可能用上一片TM16xx来驱动这个阵列。
按下按键切换模式,这个很简单的功能在当时实现得非常乱:先定义一个宏,每次如果按下按键就return
,然后在循环中多次调用它。现在我会在定时器中断里处理按键,具体来讲还有多种方法。
这些不懂的问题、不好的实现,都是经验。有些不好的实现,比如上面这个按键,不值得尝试,所以我会在回答相关问题时提供我认为合理的方法。类似的有很多,所以我一直尽力回答每个问题,帮人避雷,也好让我审视一下自己的方法。
回顾(二)
AVR单片机教程的一期介绍了简单外设的用法。我假设读者有良好的C语言基础,所以没有把基础单片机和基础C语言结合起来讲,而是在前几讲的作业题中对读者的C功底提出了较高的要求。针对当时读者的问题,我专门写了一篇元教程,强调了要广泛地了解相关知识。
从按键开始我加快了节奏,否则按照一个LED都能写4篇的速度我现在大概刚刚讲到LCD1602。原计划一期结束后还有大量内容,但是我当时已经不大想写了,所以挑了点必要的组成了第二期的6讲。
现在有读者反映第二期太难,其实不是太难而是两期之间有明显断层。在与读者交流的过程中,我还发现有很多我强调过的点还强调得不够:有些是我没讲清楚,有些是读者真的做不到,比如完成作业——我把很多关键的、实际应用中需要的问题放在了作业中,它们容易被忽略,至少没有被足够严肃地对待。
这些问题,以及上面带有责怪情感的读者提问,都是我的失职。
展望
我决定开始写AVR单片机教程第三期。
首先是查漏补缺,这还得再细分几类:
外设。I²C和定时器输入在前两期的正文中没有涉及到,会在第三期补上。
语言。我不应假设读者有良好的C基础,但我真的没法面对完完全全的新手,所以我将补充一些非单片机编程中不常用的特性,以及高级但实用的用法。
第三期的很多内容用C++讲起来会更加方便,所以我会简单介绍那些需要用的C++语法,它们也是我在自己项目中常用的C++功能子集。
作业。如前所述,很多重要的内容都在作业里,我将提供解题思路和优化建议。
然后是结构:
与C++绑定起来的对象的概念,包括基于对象与面向对象;
第二期最后提到的事件驱动范式,原本是单独的一期,将成为第三期的一部分;
有些硬件结构可以启发设计(有的可能最初来自软件),包括双缓冲、FIFO、状态机、流水线等;
大型程序和库的结构。
此外,单片机项目的共同问题,比如供电、制板、测试等,也会集中讲解一下。
由此可见,这一期“AVR单片机教程”实际上可以把前三个字去掉,尽管我们还是基于AVR平台讲解。
我设计了新的开发板,与第一版相比缩小了尺寸,去掉了部分扩展资源,使它更加核心。扩展资源被移动到了单独的模块上,多个模块提供不同方向的器件。目前还在设计,并有开放小批量订购的计划。
希望第三期能为读者建立完善的概念,能让读者学会必要的单片机编程方法,在例子中积累经验,独立设计并制作出与文首项目难度相当的单片机系统。
AVR单片机教程——第三期导语的更多相关文章
- AVR单片机教程——旋转编码器
好久没写这个系列了.今天讲讲旋转编码器. 旋转编码器好像不是单片机玩家很常用的器件,但是我们的开发板上有,原因如下: 旋转编码器挺好用的.电位器能旋转的角度有限,旋转编码器可以无限圈旋转:旋转时不连续 ...
- AVR单片机教程——数码管
先解答之前一个思考题:如果不把引脚配置为输出而写高电平,连接LED会怎样? 实验结果是,LED会亮,但相比于输出高电平的情况,亮度很低.这是为什么呢? 通过上一篇教程我们知道,引脚输入输出模式是由寄存 ...
- AVR单片机教程——数字输出
从上一篇教程中我们了解到,按键与开关的输入本质上就是数字信号的读取.这一篇教程要讲的是,控制LED的原理是数字信号的输出.数字IO是单片机编程之有别于桌面编程的各项内容中最简单.最基础的. 在讲数字信 ...
- AVR单片机教程——数字输入
我们已经学习了如何使用按键和拨动开关,不知你有没有好奇 button_down 和 switch_status 等函数是如何实现的.本篇教程带你一探究竟,让我们从按键的原理开始. 在原理图中,按键的符 ...
- AVR单片机教程——拨动开关
在按键的上方有4个拨动开关.开关与按键,在原理和使用方法上都是很类似的,但有不同的用途——按键按下后松开就会弹起,而开关可以保存其状态. <switch.h> 定义了与开关相关的函数.sw ...
- AVR单片机教程——按键动作
上一篇教程中我们学习了如何读取按键状态.而按键的动作,比如单击,至少需要两个状态才能判定,长按.双击的判定更加复杂.今天我们来学习如何使用库函数判断按键单击,以及其实现原理. 我们要实现的是:当一个按 ...
- AVR单片机教程——按键状态
好久没更新了,今天开始继续,争取日更. 今天我们来讲按键.开发板的右下角有4个按键,按下会有明显的“咔嗒”声.如何检测按键是否被按下呢?首先要把按键或直接或间接地连接到单片机上.与之前使用的4个LED ...
- AVR单片机教程——随机点亮LED
之前我们做的闪烁LED和流水灯,灯效都是循环的.这次我们来尝试一些不一样的——每一次随机选择一个LED并点亮. 要实现随机的效果,我们要用C语言标准库中的相关设施: #define RAND_MAX ...
- AVR单片机教程——流水灯
上次我们用 delay 函数与 while 循环实现了一个LED的闪烁.这一次我们把所有LED加入进来,让它们依次闪烁,形成流水灯的效果. 开发板上有4个LED,我们可以用不多的语句把循环体直接描述出 ...
随机推荐
- Python初学者随笔(一)_ 用Python写的第一个游戏“猜数字”
如标题所写,这篇随笔主要记录下学习Python过程中用Python写的第一个游戏--"猜数字"_跟着"小甲鱼"学Python,链接: https://b23.t ...
- HDU6434 Count【欧拉函数 线性筛】
HDU6434 I. Count T次询问,每次询问\(\sum_{i=1}^{n}\sum_{j=1}^{n-1}[gcd(i-j,i+j)=1]\) \(T\le 1e5, n \le 2e7\) ...
- Codeforces Round #428 (Div. 2) C. Journey (简单搜索)
题意:给你一颗树(边是无向的),从根节点向下走,统计走到每个子节点的概率,求所有叶子节点的深度乘上概率的和. 题解:每层子节点的概率等于上一层节点的概率乘\(1\)除以这层的子节点数,所以我们用\(d ...
- Linux网络文件下载
wget 以网络下载 maven 包为例 wget -c http://mirrors.shu.edu.cn/apache/maven/maven-3/3.5.4/binaries/apache-ma ...
- MySQL5.6 与 MySQL5.7 的区别
目录 编译安装区别 初始化的区别 其他区别 编译安装区别 # 5.7在编译安装的时候多了一个 boost 库 [root@db02 mysql-5.7.20]# yum install -y gcc ...
- map最最最基本用法
map<a,b>c中,a,b是变量类型 参数定义的map的名字 #include<stdio.h> #include<map> //头文件 map<int,c ...
- Caffe入门:对于抽象概念的图解分析
Caffe的几个重要文件 用了这么久Caffe都没好好写过一篇新手入门的博客,最近应实验室小师妹要求,打算写一篇简单.快熟入门的科普文. 利用Caffe进行深度神经网络训练第一步需要搞懂几个重要文件: ...
- HDU 6395 Sequence(分段矩阵快速幂)题解
题意: 已知\(A,B,C,D,P,n\)以及 \[\left\{ \begin{aligned} & F_1 = A \\ & F_2 = B\\ & F_n = C*F_{ ...
- Linux下为Chromium安装Flash插件
方案1: http://askubuntu.com/questions/158388/how-do-i-make-chromium-use-flash-from-google-chrome/21647 ...
- Spring应用上下文生命周期
Spring应用上下文生命周期整体分成四个阶段 ConfigurableApplicationContext#refresh,加载或者刷新持久化配置 ConfigurableApplicationCo ...