單片機入門第二課-點燈大師

單片機入門第二課-點燈大師

正式進入控制硬體的第一課

最后更新 2022/10/21 下午6:53
陈显达
预计阅读 12 分钟
分类
分享
标签
硬體相關

本文由網友投稿,站長是一點都不懂硬體。

作者:陳顯達

原文標題:單片機入門第二課----點燈大師

原文連結:https://www.cnblogs.com/1996-Chinese-Chen/p/16814553.html

引言

在上一博客中,我們正式開始了單片機的學習之路,講了單片機的概念,以及我們使用的 esp32 系列的單片機的 io 引腳,講了什麼是 gpio,以及相關的總線通訊概念(uart,iic,spi),脈衝調製概念(pwm),以及信號數字互轉的(adc 和 dac),板子自帶的一些功能,在今天的博客中,我會帶你們正式進入控制硬體的第一課;

不管是什麼單片機,入門第一課都是點亮 led 燈,俗稱“點燈大師”,哈哈,我們的第一課也是點燈,那我在群里,沒有讓大家去購買 led,是因為我們實際上可以使用代碼去控制 esp 板子上面的其中一個 led 燈管,當電源接通後會有一個電源燈,紅色的燈亮起,電源正常,同時還有一個燈為藍色的,默認為不顯示的,接下來我們便讓 esp32 開發板的另外一個 led 燈進行閃爍。

點燈

void setup() {

  // put your setup code here, to run once:
 pinMode(2,OUTPUT);
}

void loop() {
  digitalWrite(2, HIGH);   // sets the LED on
  delay(1000);                  // waits for a second
  digitalWrite(2, LOW);    // sets the LED off
  delay(1000);
}         

先上代碼,如上所示,即可點亮板子的另一個藍色的燈,先講一下代碼,上面的 setup,一個單片機通電,只會運行一次,即每通電一次,運行一次,下面的 loop 是循環的一個代碼,通電期間,一直循環,先運行 setup,在運行 loop,上面的 setup 顧名思義,是用來對單片機做一些配置,上面的配置就是將第二個引腳設置為輸出,即單片機向引腳 2 輸出,輸出高低電平,用來點亮 led 燈,在 esp32 中,藍色燈的引腳為 2,所以在此處我們設置引腳 2 為輸出模式,

第二個 loop 循環代碼,第一行調用了一個 digitalwrite 的方法,這個方法是給我們指定的引腳寫入高低電平,以此來給某個引腳開關通電,斷電,第一個參數為要寫入的引腳的 pin 值,即引腳值,第二個參數為需要寫入的值,high,low 這兩個為高低電平,high 通電,low 斷電,第二行代碼,則是一個延遲函數,裡面的值是毫秒值,1000,即代表暫停一秒

下面的 gif 展示了我們這次的一個運行結果,可以看到藍色燈在不停的進行閃爍。

代碼編譯和燒錄

在我們代碼寫完成之後,我們需要編譯,然後在燒寫到單片機裡面去,那每次寫完之後呢,在編輯器左上角有一個對號的按鈕,我們點擊這個按鈕之後,ide 會開始編譯我們的代碼,在編譯之後,我們需要將代碼燒錄到單片機內部,點擊對號旁邊的右箭頭按鈕,代碼開始燒錄,等待下方出現 connecting 的時候,我們要讓單片機進入下載模式,單片機上面有兩個按鈕,電源燈上面有一個按鈕,同橫著水平旁邊還有一個按鈕,當出現了 connecting 的時候需要去按住下方箭頭所指的那個按鈕不鬆手,則會寫入程式。

Arduino

我們的開發 ide 為 arduino,我之前配過 vsc 使用純 c 語言去進行開發 esp32 單片機,後面使用了 arduino,因為這個相比於純 c 來說更簡單一些,更適合入門,但是對於 c 開發,原理也是一樣的,無非就是寫法上純在差異。

在程式運行都是不停的在進行循環代碼,但是方法上一個是 main 方法,一個是 loop 其他的就是語法的區別了,arduino 是基於 c 和 c++進行封裝的,裡面的封裝更趨近於高級語言,這裡展示一下 arduino 的一些方法或者常量,數據類型等。

c 語言

而對於 c 語言來說,有的基礎不好,或者沒有深入使用過 c 語言的來講是有一些難度的,我在這裡貼一下我之前寫的一個紅外線控制智能小車的代碼,此處使用的是 esp32 原生的 c 文件來進行開發,其複雜程度和 arduino 相比還是略現複雜。

/* brushed dc motor control example
   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

/*
 * This example will show you how to use MCPWM module to control brushed dc motor.
 * This code is tested with L298 motor driver.
 * User may need to make changes according to the motor driver they use.
 */

#include <stdio.h>
#include "sdkconfig.h"
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_attr.h"
#include "driver/rmt.h"
#include "driver/mcpwm.h"
#include "soc/mcpwm_periph.h"
#include "IR_Rev.h"
// const static char *TAG = "IR_Rre Demo";

#define RECV_PIN 23  // 一体化红外接收头GPIO
uint8_t command = 0; // 接收到的ENC红外指令
int direction = 0;
float currentspeed = 0;
int currentcolor = 2;
#define GPIO_PWM0A_OUT 15 // Set GPIO 15 as PWM0A
#define GPIO_PWM0B_OUT 16 // Set GPIO 16 as PWM0B
#define GPIO_PWM1A_OUT 17
#define GPIO_PWM1B_OUT 18
#define GPIO_PWM2A_OUT 12 // Set GPIO 15 as PWM0A
#define GPIO_PWM2B_OUT 14 // Set GPIO 16 as PWM0B
#define GPIO_PWM3A_OUT 25
#define GPIO_PWM3B_OUT 26
#define RED 2
#define GREEN 4
#define BLUE 5
#define INFARE 21
static void mcpwm_example_gpio_initialize(void)
{
    printf("initializing mcpwm gpio...\n");
    mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_PWM0A_OUT);
    mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, GPIO_PWM0B_OUT);
    mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM1A, GPIO_PWM1A_OUT);
    mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM1B, GPIO_PWM1B_OUT);
    mcpwm_gpio_init(MCPWM_UNIT_1, MCPWM0A, GPIO_PWM2A_OUT);
    mcpwm_gpio_init(MCPWM_UNIT_1, MCPWM0B, GPIO_PWM2B_OUT);
    mcpwm_gpio_init(MCPWM_UNIT_1, MCPWM1A, GPIO_PWM3A_OUT);
    mcpwm_gpio_init(MCPWM_UNIT_1, MCPWM1B, GPIO_PWM3B_OUT);
}
// forwards he forward 替换实现顺时针吹风和逆时针吹风
/**
 * @brief motor moves in forward direction, with duty cycle = duty %
 */
static void brushed_motor_forward(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, float duty_cycle)
{
    mcpwm_set_signal_low(mcpwm_num, timer_num, MCPWM_OPR_A);
    mcpwm_set_duty(mcpwm_num, timer_num, MCPWM_OPR_B, duty_cycle);
    mcpwm_set_duty_type(mcpwm_num, timer_num, MCPWM_OPR_B, MCPWM_DUTY_MODE_0); // call this each time, if operator was previously in low/high state
}
static void brushed_motor_forwards(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, float duty_cycle)
{
    ESP_ERROR_CHECK(mcpwm_set_signal_low(mcpwm_num, timer_num, MCPWM_OPR_B));
    ESP_ERROR_CHECK(mcpwm_set_duty(mcpwm_num, timer_num, MCPWM_OPR_A, duty_cycle));
    ESP_ERROR_CHECK(mcpwm_set_duty_type(mcpwm_num, timer_num, MCPWM_OPR_A, MCPWM_DUTY_MODE_0)); // call this each time, if operator was previously in low/high state
}
// forwards he forward 替换实现顺时针吹风和逆时针吹风
/**
 * @brief motor moves in forward direction, with duty cycle = duty %
 */
static void brushed_motor_backward(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, float duty_cycle)
{
    mcpwm_set_signal_low(mcpwm_num, timer_num, MCPWM_OPR_B);
    mcpwm_set_duty(mcpwm_num, timer_num, MCPWM_OPR_A, duty_cycle);
    mcpwm_set_duty_type(mcpwm_num, timer_num, MCPWM_OPR_A, MCPWM_DUTY_MODE_0); // call this each time, if operator was previously in low/high state
}
static void brushed_motor_backwards(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, float duty_cycle)
{
    ESP_ERROR_CHECK(mcpwm_set_signal_low(mcpwm_num, timer_num, MCPWM_OPR_A));
    ESP_ERROR_CHECK(mcpwm_set_duty(mcpwm_num, timer_num, MCPWM_OPR_B, duty_cycle));
    ESP_ERROR_CHECK(mcpwm_set_duty_type(mcpwm_num, timer_num, MCPWM_OPR_B, MCPWM_DUTY_MODE_0)); // call this each time, if operator was previously in low/high state
}

/**
 * @brief motor stop
 */
static void brushed_motor_stop(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
{
    mcpwm_set_signal_low(mcpwm_num, timer_num, MCPWM_OPR_A);
    mcpwm_set_signal_low(mcpwm_num, timer_num, MCPWM_OPR_B);
}

static void setspeed(uint8_t command)
{
    if ((uint8_t)command == 22)
    {
        printf("%d\n", 22);
        currentspeed = 10;
    }
    else if ((uint8_t)command == 12)
    {
        printf("%d\n", 12);
        currentspeed = 20;
    }
    else if ((uint8_t)command == 24)
    {
        printf("%d\n", 24);
        currentspeed = 30;
    }
    else if ((uint8_t)command == 94)
    {
        printf("%d\n", 94);
        currentspeed = 40;
    }
    else if ((uint8_t)command == 8)
    {
        printf("%d\n", 8);
        currentspeed = 50;
    }
    else if ((uint8_t)command == 28)
    {
        printf("%d\n", 28);
        currentspeed = 60;
    }
    else if ((uint8_t)command == 90)
    {
        printf("%d\n", 90);
        currentspeed = 70;
    }
    else if ((uint8_t)command == 66)
    {
        printf("%d\n", 66);
        currentspeed = 80;
    }
    else if ((uint8_t)command == 82)
    {
        printf("%d\n", 82);
        currentspeed = 90;
    }
    else if ((uint8_t)command == 74)
    {
        printf("%d\n", 74);
        currentspeed = 100;
    }
}
static void head(float speed)
{
    brushed_motor_forward(MCPWM_UNIT_0, MCPWM_TIMER_0, speed);
    brushed_motor_forwards(MCPWM_UNIT_0, MCPWM_TIMER_1, speed);
    brushed_motor_forward(MCPWM_UNIT_1, MCPWM_TIMER_0, speed);
    brushed_motor_forwards(MCPWM_UNIT_1, MCPWM_TIMER_1, speed);
}
static void last(float speed)
{
    brushed_motor_backward(MCPWM_UNIT_0, MCPWM_TIMER_0, speed);
    brushed_motor_backwards(MCPWM_UNIT_0, MCPWM_TIMER_1, speed);
    brushed_motor_backward(MCPWM_UNIT_1, MCPWM_TIMER_0, speed);
    brushed_motor_backwards(MCPWM_UNIT_1, MCPWM_TIMER_1, speed);
}
static void left(float speed)
{
    mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_A);
    mcpwm_set_signal_low(MCPWM_UNIT_1, MCPWM_TIMER_0, MCPWM_OPR_B);
}
static void right(float speed)
{
    mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B);
    mcpwm_set_signal_low(MCPWM_UNIT_1, MCPWM_TIMER_1, MCPWM_OPR_A);
}
/**
 * @brief Configure MCPWM module for brushed dc motor
 */
static void mcpwm_example_brushed_motor_control(void *arg)
{
    // 1. mcpwm gpio initialization
    mcpwm_example_gpio_initialize();

    // 2. initial mcpwm configuration
    printf("Configuring Initial Parameters of mcpwm...\n");
    mcpwm_config_t pwm_config;
    pwm_config.frequency = 1000; // frequency = 500Hz,
    pwm_config.cmpr_a = 0;       // duty cycle of PWMxA = 0
    pwm_config.cmpr_b = 0;       // duty cycle of PWMxb = 0
    pwm_config.counter_mode = MCPWM_UP_COUNTER;
    pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
    ESP_ERROR_CHECK(mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config)); // Configure PWM0A & PWM0B with above settings
    mcpwm_config_t pwm_configs;
    pwm_configs.frequency = 1000; // frequency = 500Hz,
    pwm_configs.cmpr_a = 0;       // duty cycle of PWMxA = 0
    pwm_configs.cmpr_b = 0;       // duty cycle of PWMxb = 0
    pwm_configs.counter_mode = MCPWM_UP_COUNTER;
    pwm_configs.duty_mode = MCPWM_DUTY_MODE_0;
    ESP_ERROR_CHECK(mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_1, &pwm_configs)); // Configure PWM0A & PWM0B with above settings

    mcpwm_config_t pwm_configA;
    pwm_configA.frequency = 1000; // frequency = 500Hz,
    pwm_configA.cmpr_a = 0;       // duty cycle of PWMxA = 0
    pwm_configA.cmpr_b = 0;       // duty cycle of PWMxb = 0
    pwm_configA.counter_mode = MCPWM_UP_COUNTER;
    pwm_configA.duty_mode = MCPWM_DUTY_MODE_0;
    ESP_ERROR_CHECK(mcpwm_init(MCPWM_UNIT_1, MCPWM_TIMER_0, &pwm_configA)); // Configure PWM0A & PWM0B with above settings
    mcpwm_config_t pwm_configAs;
    pwm_configAs.frequency = 1000; // frequency = 500Hz,
    pwm_configAs.cmpr_a = 0;       // duty cycle of PWMxA = 0
    pwm_configAs.cmpr_b = 0;       // duty cycle of PWMxb = 0
    pwm_configAs.counter_mode = MCPWM_UP_COUNTER;
    pwm_configAs.duty_mode = MCPWM_DUTY_MODE_0;
    ESP_ERROR_CHECK(mcpwm_init(MCPWM_UNIT_1, MCPWM_TIMER_0, &pwm_configAs)); // Configure PWM0A & PWM0B with above settings */ */
    while (1)
    {
        command = IRrecvReadIR();


        printf("IR Command is %02X\n", command);
        printf("IR 111 is %d\n", (uint8_t)command);
        if ((uint8_t)command == 69)
        {
            brushed_motor_stop(MCPWM_UNIT_0, MCPWM_TIMER_0);
            brushed_motor_stop(MCPWM_UNIT_0, MCPWM_TIMER_1);
            brushed_motor_stop(MCPWM_UNIT_1, MCPWM_TIMER_0);
            brushed_motor_stop(MCPWM_UNIT_1, MCPWM_TIMER_1);
        }
        else if ((uint8_t)command == 64)
        {
            direction = 64;
            head(currentspeed);
        }
        else if ((uint8_t)command == 25)
        {
            direction = 25;
            last(currentspeed);
        }
        else if ((uint8_t)command == 7)
        {
            printf("IR 32 is %d\n", (uint8_t)command);
            left(currentspeed);
        }
        else if ((uint8_t)command == 9)
        {
            printf("IR 23 is %d\n", (uint8_t)command);
            right(currentspeed);
        }
        else
        {
            printf(" %d\n", direction);
            setspeed(command);
            if (direction == 64)
            {
                head(currentspeed);
            }
            else if (direction == 25)
            {
                last(currentspeed);
            }
        }
    }
}
static void openlight(void *arg)
{
    gpio_set_level(INFARE, 1);
    while (1)
    {

        gpio_set_level(currentcolor, 1);
        vTaskDelay(200 / portTICK_PERIOD_MS);
        gpio_set_level(currentcolor, 0);
        if(currentcolor==2)
        {
            currentcolor=4;
        }
        else if (currentcolor==4)
        {
            currentcolor=5;
        }
        else if (currentcolor==5)
        {
            currentcolor=2;
        }
    }

}
void app_main(void)
{
    IRrecvInit(RECV_PIN, 3);
    gpio_set_direction(INFARE, GPIO_MODE_OUTPUT);
    gpio_set_direction(RED, GPIO_MODE_OUTPUT);
    gpio_set_direction(GREEN, GPIO_MODE_OUTPUT);
    gpio_set_direction(BLUE, GPIO_MODE_OUTPUT);
    xTaskCreate(mcpwm_example_brushed_motor_control, "mcpwm_examlpe_brushed_motor_control", 4096, NULL, 5, NULL);
    xTaskCreate(openlight, "openlight", 4096, NULL, 5, NULL);
}

而令我最喜歡 arduino 的一點是,我們需要使用一些第三方庫的時候,這裡的擴展相比 vsc 更容易找一些,c 的話在插件市場極大可能找不到,需要在網上自己搜索,找到 c 語言寫好的文件,然後 include 進來再去使用,找的話有點難度,對於紅外線來講,上次我在網上找就找了挺久的一段時間。而在 arduino 我只需在管理庫界面搜索我想要的庫或者關鍵字都可以找到,emmm,我覺得就像 nuget 一樣簡單,哈哈,所以我更喜歡用這個一點。

在這裡,我們就可以根據關鍵字,類型去搜索我們想要的第三方庫,很方便,同時有的第三方庫也是有例子可以直接使用,總體來說,作為簡單入門,arduino 還是很不錯的一個選擇。

結語

好啦,今天的點燈第一課就到這裡啦,如果又不懂的可以隨時問我,可以加這個群一起來學習單片機,後面還會開 stm32 系列的課程,ide 的話可以看上一篇博客中的下載地址是有百度網盤的地址,同時群文件也有,有需要的可以下載啦,我們系列教程會出到可以自己做一個智能小車為止。

Keep Exploring

延伸阅读

更多文章
同分类 2025/8/13

推薦一款高性能狀態機管理解決方案

在實際軟體開發中,尤其是工業軟體,每一款設備都有複雜的狀態以及狀態之間的切換的功能需求,在這種情況下,如何管理狀態以及狀態之間切換,和對應狀態下的功能控制,成為非常重要的一個問題。

继续阅读