一、外设引脚
(1)电机原理电路
首先我们来了解一下电机的引脚设置。
这个电路还是比较简单的。这个电路中,VCC_3V3和R65、C71、C72组成了一个RC低频滤波器,来确保L9110s芯片的VCC端口接入的是稳定的电压。
电路的另一部分是由L9110s和电机组成的另一部分构成的电机电路。我们首先来看看L9110s的芯片引脚真值表:
可以看出,在L9110s电路中,输入IA与输出OA同相,输入IB与输出IB同相。即 IA = OA,IB = OB。
并且在该真值表中可以看出电机 MOTOR1 的运动情况为:V+和V-电压同相,同为H或L时,电机停止运行;V+为H,V-为L,则电机右转;V+为L,V-为H,则电机左转。
(2)蜂鸣器
蜂鸣器的电路原理图
可以看出蜂鸣器电路中主要靠三极管的集电极电路中的电压电流进行响应。在BEEP引脚设置为高电平H时,此时三极管打开,蜂鸣器BEEP1两引脚的电压差和电流增大,蜂鸣器响。
二、实验代码:
(1)初始化定义
首先了解一下头文件:
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
这个代码主要还是设置电路原理中的各个引脚,在这个头文件中主要设置的就是MOTOR A、MOTOR B、BEEP三个引脚的设置和打开引脚PIN的功能,具体情况可以看前三个实验中的头文件部分。
enum
{
MOTOR_STOP,
MOTOR_LEFT,
MOTOR_RIGHT
};
然后就定义枚举类型,其中包含了三个枚举常量:
`MOTOR_STOP`:表示电机停止状态。
`MOTOR_LEFT`:表示电机左转状态。
`MOTOR_RIGHT`:表示电机右转状态。
/* 电机控制 */
void motor_ctrl(rt_uint8_t turn)
{
if (turn == MOTOR_STOP)
{
rt_pin_write(PIN_MOTOR_A, PIN_LOW);
rt_pin_write(PIN_MOTOR_B, PIN_LOW);
}
else if (turn == MOTOR_LEFT)
{
rt_pin_write(PIN_MOTOR_A, PIN_LOW);
rt_pin_write(PIN_MOTOR_B, PIN_HIGH);
}
else if (turn == MOTOR_RIGHT)
{
rt_pin_write(PIN_MOTOR_A, PIN_HIGH);
rt_pin_write(PIN_MOTOR_B, PIN_LOW);
}
else
{
LOG_D("err parameter ! Please enter 0-2.");
}
}
在这个函数中,定义一个电机的旋转方式函数。在这个函数中,根据输入的参数是否等于之前定义的三个枚举变量来定义引脚的值来控制电机的运行方式。
void beep_ctrl(rt_uint8_t on)
{
if (on)
{
rt_pin_write(PIN_BEEP, PIN_HIGH);
}
else
{
rt_pin_write(PIN_BEEP, PIN_LOW);
}
}
在这个代码中,定义一个蜂鸣器的控制函数。如果这个函数的输入参数不为0,则定义蜂鸣器的引脚为高电平H,蜂鸣器响,否则不响。
/* 中断回调 */
void irq_callback(void *args)
{
rt_uint32_t sign = (rt_uint32_t)args;
switch (sign)
{
case PIN_KEY0:
motor_ctrl(MOTOR_LEFT);
LOG_D("KEY0 interrupt. motor turn left.");
break;
case PIN_KEY1:
motor_ctrl(MOTOR_RIGHT);
LOG_D("KEY1 interrupt. motor turn right.");
break;
case PIN_KEY2:
motor_ctrl(MOTOR_STOP);
LOG_D("KEY2 interrupt. motor stop.");
break;
default:
LOG_E("error sign= %d !", sign);
break;
}
}
这个函数的作用就是读取按键的值来控制电机,如果按下的是按键KEY0,则电机左转;如果按下的按键KEY1,则电机右转;如果按下的按键KEY2,则电机停止转动。
(2)主函数
int main(void)
{
unsigned int count = 1;
/* 设置按键引脚为输入模式 */
rt_pin_mode(PIN_KEY0, PIN_MODE_INPUT_PULLUP);
rt_pin_mode(PIN_KEY1, PIN_MODE_INPUT_PULLUP);
rt_pin_mode(PIN_KEY2, PIN_MODE_INPUT_PULLUP);
rt_pin_mode(PIN_WK_UP, PIN_MODE_INPUT_PULLDOWN);
/* 设置电机控制引脚为输入模式 */
rt_pin_mode(PIN_MOTOR_A, PIN_MODE_OUTPUT);
rt_pin_mode(PIN_MOTOR_B, PIN_MODE_OUTPUT);
/* 设置蜂鸣器引脚为输出模式 */
rt_pin_mode(PIN_BEEP, PIN_MODE_OUTPUT);
/* 设置按键中断模式与中断回调函数 */
rt_pin_attach_irq(PIN_KEY0, PIN_IRQ_MODE_FALLING, irq_callback, (void *)PIN_KEY0);
rt_pin_attach_irq(PIN_KEY1, PIN_IRQ_MODE_FALLING, irq_callback, (void *)PIN_KEY1);
rt_pin_attach_irq(PIN_KEY2, PIN_IRQ_MODE_FALLING, irq_callback, (void *)PIN_KEY2);
/* 使能中断 */
rt_pin_irq_enable(PIN_KEY0, PIN_IRQ_ENABLE);
rt_pin_irq_enable(PIN_KEY1, PIN_IRQ_ENABLE);
rt_pin_irq_enable(PIN_KEY2, PIN_IRQ_ENABLE);
while (count > 0)
{
if (rt_pin_read(PIN_WK_UP) == PIN_HIGH)
{
rt_thread_mdelay(50);
if (rt_pin_read(PIN_WK_UP) == PIN_HIGH)
{
LOG_D("WK_UP pressed. beep on.");
beep_ctrl(1);
}
}
else
{
beep_ctrl(0);
}
rt_thread_mdelay(10);
count++;
}
return 0;
}
首先在main函数里面先定义一下各个引脚的输入输出情况,其中PIN_WK_UP中的PIN_MODE_INPUT_PULLDOWN为0x03。
关于rt_pin_attach_irq()函数的介绍:
1. `rt_pin_attach_irq(PIN_KEY0, PIN_IRQ_MODE_FALLING, irq_callback, (void *)PIN_KEY0);
这行代码将键盘的按键 0(通常是一个数字引脚)设置为下降沿触发的中断模式,并将中断回调函数 `irq_callback` 与之关联。`(void *)PIN_KEY0` 是将按键 0 的引脚号传递给回调函数作为参数。
2. `rt_pin_attach_irq(PIN_KEY1, PIN_IRQ_MODE_FALLING, irq_callback, (void *)PIN_KEY1);
这行代码将键盘的按键 1 设置为下降沿触发的中断模式,并将中断回调函数 `irq_callback` 与之关联。`(void *)PIN_KEY1` 是将按键 1 的引脚号传递给回调函数作为参数。
3. `rt_pin_attach_irq(PIN_KEY2, PIN_IRQ_MODE_FALLING, irq_callback, (void *)PIN_KEY2);
这行代码将键盘的按键 2 设置为下降沿触发的中断模式,并将中断回调函数 `irq_callback` 与之关联。`(void *)PIN_KEY2` 是将按键 2 的引脚号传递给回调函数作为参数。
关于rt_pin_irq_enable()函数的介绍:
1. `rt_pin_irq_enable(PIN_KEY0, PIN_IRQ_ENABLE);
这行代码使能了按键 0 的中断功能。`PIN_IRQ_ENABLE` 是一个宏定义,用于表示使能中断。
2. `rt_pin_irq_enable(PIN_KEY1, PIN_IRQ_ENABLE);
这行代码使能了按键 1 的中断功能。
3. `rt_pin_irq_enable(PIN_KEY2, PIN_IRQ_ENABLE);
这行代码使能了按键 2 的中断功能。
最后面那段while()函数主要用于对按键WK_UP的按键值读取,读取到高电平相应的值H后,蜂鸣器就会响,若按键WK_UP没有按下,则电压值还是为低电平L。
(3)拓展
为什么蜂鸣器没用中断呢?
我认为是因为蜂鸣器只是在按键按下时才响,松开时就不响。如果用中断的话,蜂鸣器可能只设置到引脚电平为高,没有设置到松开时电平为低,比较难达到目标的情况,所以就没用中断。
为什么电机没用循环函数呢?
如果电机也用循环函数的话,主函数需要的代码长度比较长,代码也比较杂乱,而且也只能用从上到下依次扫描实现。用中断的话,可以立即反应出是哪个按键设置电机按钮,就不需要从上到下依次扫描各个按键的值。