每日一言
当你想要放弃时,想想最初为什么出发。
案例:测速小车通过串口反馈到上位机
这边我说一句真正的学习嵌入式的孩子一句话:我们要实现一个功能的话必须要先看模块的功能是怎么实现的,因为嵌入式和软件学jave的不一样,嵌入式每个模块自己有自己的通信关系,或者是说触发手段,所以说嵌入式主要是学习模块的特性和使用
比如这边这个测速模块
这三种都可以用
这个是码盘(买小车配件的时候都会送)
我们这个测速模块的原理是什么呢?
看到这个码盘上面的空格了吗,因为我们小车轮子转的时候这个码盘会跟着轮子转动,那么模块的机制是这样的,如果没有被码盘黑色部分挡住那么光线就穿不过去了,模块就是高电平,模块的灯会灭,要是没有被挡住也就是光线穿过了,那么就是低电平,灯也会亮,我们可以根据这个特点
这个特点是什么呢:是不是高电平向低电平转变啊 那是不是就是下降沿啊,那么我们的外部中断0、1、2、3是不是都有这个特点啊,可以利用外部中断条件为下降沿,这个方法我们来计算1s之内有多少个下降沿,也就是有多少个外部中断来测速
我们这个码盘的话是有20个格子,那么我们可以利用算出一个格子代表的长度
我是这样算的
我的轮子的半径是3.4cm 那么利用周长的公式就算的出一个格子代表的长度了,那么1.06cm的话,我们这边为了方便就直接当做是一个格子1cm了(好算多了)
官方解答:
槽型光耦测速模块的原理,简单说就是 “红外遮挡→电信号变化→计数 / 测速”,分 3 步理解:
1. 核心结构:红外发射 + 接收
模块中间有个槽,槽一侧是 红外发光二极管(持续发红外光),另一侧是 光电三极管 / 接收管(检测红外光)。
2. 遮挡触发信号变化
无遮挡:红外光直射到接收管,接收管导通,模块输出 低电平(或默认电平,依模块设计)。
有遮挡:物体(如电机码盘的齿 / 孔)穿过槽,挡住红外光,接收管截止,模块输出 高电平。
电机转一圈,码盘的齿 / 孔会多次遮挡槽,模块就会输出 一串高低电平脉冲。
3. 测速 / 计数逻辑
- 计数:数脉冲个数,就能知道码盘转了多少齿(比如码盘 1 圈 20 个孔,20 个脉冲 = 1 圈)。
- 测速:用定时器记录 “单位时间(如 1 秒)内的脉冲数”,结合码盘齿数、轮子周长,就能算出转速 / 线速度。
公式参考:转速 = (脉冲数 ÷ 码盘齿数) ÷ 时间 、 线速度 = (脉冲数 ÷ 码盘齿数)× 轮子周长 ÷ 时间
举个栗子(电机测速)
- 码盘 1 圈 20 个孔 → 每转 1 圈,模块输出 20 个脉冲。
- 定时器测 1 秒内收到 100 个脉冲 → 电机 1 秒转 100÷20=5 圈 → 若轮子周长 0.1 米,线速度就是 5×0.1=0.5米/秒。
简单说,就是靠 “红外通断产生脉冲,数脉冲算速度 / 圈数” ,很适合电机、小车这类场景的测速 / 计数~
开始写代码
Main.c文件的代码
根据前面的介绍知道了我们需要使用外部中断0,那么我们根据芯片手册得知外部中断0对应的引脚是P3的2口,那么我们需要进行引脚的调用sbit speedIO = P3^2;
随后我们需要初始化外部中断,我们根据手册
所以我们就会写外部中断0的初始化函数了
void INT0_init()
{
EX0 = 1;
IT0 = 1;
}
那么我们是不是要写一个外部中断函数,就是当中断的时候也就是过了码盘的一个格子了(一个脉冲信号),我们需要将它累加加起来,所以我们要先定义一个变量用于中断函数里面的累加,我定义成unsigned int countspeed= 0; 无符号的int可以可以存储到65536 并初始化为0,随后我们的中断函数就可以进行++了
我们这个状态位flag为1的时候说明就是到1s了那么我们就发送数据到串口
这个sprintf这个函数的意思就是拼接字符串的作用,因为我们的串口不是需要发送的数据是字符吗,
但是我们的speed又是数字类型的,而且我们也需要发送一些cm/s单位这些的,所以我想到了这个方法,将这些固定的字符和我们变换的数字,通过这个方法就可以存放到数组,然后我们把数组名作为这个sendString的参数就可以达到我们的要求了,最后还要将flag重置为0等待下一个1S的到来
注:要用其他文件的变量记得加上extern就可以了,说过很多遍了哦
记住一定要记得这个知识点springf函数
这个是电机的代码,也不需要讲解了
电机的.h文件 声明函数
串口的.c文件
这边的代码也不需要讲解啊,都是之前的代码,程序员要会搬砖
串口的声明函数文件
定时器.c的文件代码
我们这边用定时器0来配置一个0.5ms也就是之前PWM的舵机或者是调速小车的时候都是用的这个代码,直接搬过来用就是了
定时器中断要讲解一下,我们需要定的是1s那么就是2000个0.5ms这样,当我们到1s的时候我们需要进行cnt重置为0,这个cnt是来计算0.5ms的,
需要将此时经过1s的countspeed的值赋值给speed 注:这个speed是自己定义的,用于存储countspeed的值,赋值完之后再将countspeed重置为0
最后一点,我们不是想要每1s发送数据给串口,那么我们就需要做一个状态位,首先在这边1s的时候我们设置这个flag为1,那么main函数那边也只有flag==1的时候才可以进行发送数据到串口助手,后续到main.c代码去看
最后展示效果