admin管理员组

文章数量:1573361

VSCode+IDF环境使用

  • 环境搭建
  • 第一个程序hello world
  • 编译、调试
  • 快速入门,使用
    • freeRTOS创建任务
      • 遇坑
    • ADC采集程序
    • PWM输出程序
    • wifi通讯(含TCP通讯)
    • ble通讯
    • lcd显示
    • CAN通讯

环境搭建

抱歉!用Arduino,不得劲!改用IDF。(所以,Arduino不再更新…)

环境下载: 链接

环境教程: 链接

ps:乐鑫官网下载离线安装包链接

第一个程序hello world

对于 Hello world 程序,我们可以看到目录结构如下:

    - hello_world/
             - Makefile
             - main/       - hello_world_main.c
                           - component.mk
             - README.md
             - sdkconfig(编译生成或者自己添加)
             - build/(编译生成)

按照环境教程信息,创建一个hello world工程,会自动生成代码:

#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"

void app_main(void)
{
    printf("Hello world!\n");

    /* Print chip information */
    esp_chip_info_t chip_info;
    uint32_t flash_size;
    esp_chip_info(&chip_info);
    printf("This is %s chip with %d CPU core(s), %s%s%s%s, ",
           CONFIG_IDF_TARGET,
           chip_info.cores,
           (chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "",
           (chip_info.features & CHIP_FEATURE_BT) ? "BT" : "",
           (chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "",
           (chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : "");

    unsigned major_rev = chip_info.revision / 100;
    unsigned minor_rev = chip_info.revision % 100;
    printf("silicon revision v%d.%d, ", major_rev, minor_rev);
    if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) {
        printf("Get flash size failed");
        return;
    }

    printf("%" PRIu32 "MB %s flash\n", flash_size / (uint32_t)(1024 * 1024),
           (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");

    printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size());

    for (int i = 10; i >= 0; i--) {
        printf("Restarting in %d seconds...\n", i);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
    printf("Restarting now.\n");
    fflush(stdout);
    esp_restart();
}

这是我的板子信息:

esptool.py v4.7.0
Serial port COM7
Connecting...
Chip is ESP32-S3 (QFN56) (revision v0.1)
Features: WiFi, BLE, Embedded Flash 4MB (XMC), Embedded PSRAM 2MB (AP_3v3)
Crystal is 40MHz
MAC: dc:54:75:df:72:30
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Flash will be erased from 0x00000000 to 0x00005fff...
Flash will be erased from 0x00010000 to 0x00048fff...
Flash will be erased from 0x00008000 to 0x00008fff...
Compressed 21072 bytes to 13056...
Wrote 21072 bytes (13056 compressed) at 0x00000000 in 0.4 seconds (effective 417.2 kbit/s)...
Hash of data verified.
Compressed 231088 bytes to 122492...
Wrote 231088 bytes (122492 compressed) at 0x00010000 in 2.3 seconds (effective 819.4 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 103...
Wrote 3072 bytes (103 compressed) at 0x00008000 in 0.1 seconds (effective 480.4 kbit/s)...
Hash of data verified.

编译、调试

通过串口来烧写,配置好端口与波特率即可。

如果是支持usb调试移步到:链接

ESP32S3各个管脚使用需要注意的情况说明:链接

快速入门,使用

首先,默认正常有单片机的基础,即可快速入门,否则,建议还是看arduino的方式进行编译。

气氛烘托到这了,这篇文章可以快速的看一下(不要超过1分钟):ESP32 基础篇:ESP-IDF 编程指南

做软件开发正常来说,你应该懂硬件的,总之,不管你懂不懂,先下载下来看看呗~~~:来吧,附上手册下载地址

啥?你说没找到API接口手册?那好,来来来,拿走:链接

freeRTOS创建任务

这个链接写的很好,我就不用再写一遍了, 哈哈哈…FreeRTOS入门–任务

直接上代码:

创建任务:

/*
        BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, // 函数指针, 任务函数
        const char * const pcName, // 任务的名字
        const configSTACK_DEPTH_TYPE usStackDepth, // 栈大小,单位为word,10表示40字节
        void * const pvParameters, // 调用任务函数时传入的参数
        UBaseType_t uxPriority, // 优先级   优先级的取值范围是:0~(configMAX_PRIORITIES – 1),数值越大优先级越高。
        TaskHandle_t * const pxCreatedTask ); // 任务句柄, 以后使用它来操作这个任务
    */
    xTaskCreate(frt_wifi_Task, "frt_wifi_Task", (4*1024), NULL, 5, NULL);


任务线程:

void frt_wifi_Task( void *pvParameters )
{
    for( ;; )
    {
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        printf("111111111111111\n");
    }
}

遇坑

什么?你说不停重启?,我不允许你有问题!!!
来来来,移步到:链接

ADC采集程序

#include "driver/adc.h"
 
void adc_init() {
    adc1_config_width(ADC_WIDTH_BIT_12);   // 设置ADC分辨率
    adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_11); // 设置通道0的电压衰减
}
 
uint16_t adc_read(adc1_channel_t channel) {
    return adc1_get_raw(channel); // 读取通道的原始ADC值
}
 
void app_main() {
    adc_init(); // 初始化ADC
 
    while (1) {
        uint16_t adc_value = adc_read(ADC1_CHANNEL_0); // 读取通道0的ADC值
        // 处理adc_value
    }
}

很多人问,网上教程都是ADC1,没有ADC2的吗?好吧,拿走:

	//读取ADC2的电压值
	float adc_voltage = 0.0;

    int adc_value;
    adc2_get_raw(ADC_CHANNEL_7, ADC_BITWIDTH_12, &adc_value);
    adc_voltage = adc_value * (3.3 / 4095); // 根据采样值计算电压值并存储到adc_voltage变量中

    return adc_voltage;

ADC2的坑,我已经整理好了,在这里:链接

ESP32S3 ADC DMA使用记录(坑记录)(大牛欢迎给出建议)链接

PWM输出程序

关于PWM,官方的接口采用的LED的渐变作为API,说实话,我感觉太奇怪了,,,

按照官方的说法:
LED 控制器 (LEDC) 主要用于控制 LED,也可产生 PWM 信号用于其他设备的控制。该控制器有 8 路通道,可以产生独立的波形,驱动 RGB LED 等设备。

所以,代码中头文件是#include “driver/ledc.h”。

直接上代码

#include "driver/ledc.h"

ledc_channel_config_t 	g_ledc_ch; //PWM配置结构体

void pwm_init(void) {

  ledc_timer_config_t ledc_timer={
      .duty_resolution = LEDC_TIMER_12_BIT,//LEDC_TIMER_13_BIT, //PWM分辨率
      .freq_hz = 1000, //频率
      .speed_mode = LEDC_LOW_SPEED_MODE,
      .timer_num = LEDC_TIMER_0, //选择定时器
  };

  	ledc_timer_config(&ledc_timer);					//设置定时器PWM模式


    //PWM通道0配置->GPIO13->LED灯
	g_ledc_ch.channel    = LEDC_CHANNEL_0;		//PWM通道
	g_ledc_ch.duty       = 1000;						//占空比
	g_ledc_ch.gpio_num   = 13;					//IO映射
	g_ledc_ch.speed_mode = LEDC_LOW_SPEED_MODE;	//速度
	g_ledc_ch.timer_sel  = LEDC_TIMER_0;			//选择定时器
	ledc_channel_config(&g_ledc_ch);				//配置PWM

}


void z_set_pwm(uint16_t duty)
{
  ledc_set_duty(LEDC_LOW_SPEED_MODE,0,duty);
  ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
}

wifi通讯(含TCP通讯)

你玩ESP32很多时候也是奔着wifi来的,那么这边就把wifi程序贴出来,亲测哦!

不废话,上代码:

//先是wifi初始化(sta模式),用于连接路由器

// SSID & Password
#define client_ssid "你自己填写呗"      // 你的SSID
#define client_password "你自己填写呗"  // 你的密码

static const char *TAG = "wifi";
static u8_t g_wifi_status = 0;
/** 事件回调函数
 * @param arg   用户传递的参数
 * @param event_base    事件类别
 * @param event_id      事件ID
 * @param event_data    事件携带的数据
 * @return 无
*/
static void wifi_event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data)
{
    if(event_base == WIFI_EVENT)
    {
        switch (event_id)
        {
          case WIFI_EVENT_STA_START:      //WIFI以STA模式启动后触发此事件
          {
            g_wifi_status = 0;
            esp_wifi_connect();         //启动WIFI连接
          }
          break;

          case WIFI_EVENT_STA_CONNECTED:  //WIFI连上路由器后,触发此事件
          {
            g_wifi_status = 1;
            ESP_LOGI(TAG, "connected to AP");
          }
          break;

          case WIFI_EVENT_STA_DISCONNECTED:   //WIFI从路由器断开连接后触发此事件
          {
            g_wifi_status = 0;
            esp_wifi_connect();             //继续重连
            ESP_LOGI(TAG,"connect to the AP fail,retry now");
          }
          break;

          default:
          {
            ESP_LOGI(TAG,"unknown event");
          }
          break;
        }
    }
    if(event_base == IP_EVENT)                  //IP相关事件
    {
        switch(event_id)
        {
            case IP_EVENT_STA_GOT_IP:           //只有获取到路由器分配的IP,才认为是连上了路由器
            {
              g_wifi_status = 2;
              ESP_LOGI(TAG,"get ip address:%d.",g_wifi_status);
            }
            break;
        }
    }
}

void z_wifi_init(void)
{
  ESP_ERROR_CHECK(esp_netif_init());  //用于初始化tcpip协议栈
  ESP_ERROR_CHECK(esp_event_loop_create_default());       //创建一个默认系统事件调度循环,之后可以注册回调函数来处理系统的一些事件
  esp_netif_create_default_wifi_sta();    //使用默认配置创建STA对象

  //初始化WIFI
  wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
  ESP_ERROR_CHECK(esp_wifi_init(&cfg));

   //注册WIFI事件回调函数
  ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT,ESP_EVENT_ANY_ID,&wifi_event_handler,NULL));
  ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT,IP_EVENT_STA_GOT_IP,&wifi_event_handler,NULL));

  //WIFI配置
  wifi_config_t wifi_config = 
  { 
      .sta = {
          .ssid = client_ssid,             //WIFI的SSID
          .password = client_password,      //WIFI密码
          .threshold.authmode = WIFI_AUTH_WPA2_PSK,   //加密方式

          .pmf_cfg ={
              .capable = true,
            .required = false,
          }
      },
  };

  //启动WIFI
  ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );         //设置工作模式为STA
  ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );   //设置wifi配置
  ESP_ERROR_CHECK(esp_wifi_start() );                         //启动WIFI

  ESP_LOGI(TAG, "wifi_init_sta finished.");
}

对,你连上了路由器,那么,你需要链接socket呀,来上代码:

static int sock=0;
void z_wifi_socket_init(void)
{
  g_wifi_status = 2;

  // 创建socket:socket();
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0)
    {
        ESP_LOGE(TAG, "create socket failed!");
        return;
    }
    ESP_LOGI(TAG, "create socket successfully!");

    // 初始化server的地址结构体sockaddr_in
    struct sockaddr_in destaddr = {0};
    destaddr.sin_family = AF_INET;
    destaddr.sin_port = htons(7777);                      // 填写网络调试助手服务端实际端口
    destaddr.sin_addr.s_addr = inet_addr("192.168.x.xxx"); // 填写网络调试助手服务端实际IP地址(ip地址自己填写呗)

    // 建立socket连接:
    socklen_t len = sizeof(struct sockaddr);
    if (connect(sock, (struct sockaddr *)&destaddr, len) < 0)
    {
        ESP_LOGE(TAG, "connect to server failed!");
        close(sock);
        return;
    }
    ESP_LOGI(TAG, "connect to server successfully!");

    g_wifi_status = 3;
}

那么,来发送一下数据:

void z_wifi_process(void)
{
    //进行tcp通讯
    if(g_wifi_status == 3)
    {
      ESP_LOGI(TAG, "send data...");
        // 发送数据
        const char *send_data = "hello,world!";
        send(sock, send_data, strlen(send_data), 0);//发送数据
    }
    else if( g_wifi_status == 2 )
    {
      ESP_LOGI(TAG, "z_wifi_socket_init");
      z_wifi_socket_init();
    }
    else
    {
      ESP_LOGI(TAG, "waiting for wifi connection...");
    }
}

运行结果:
1、连上路由器:
2、socket连接成功:

3、发送hello world数据:

ble通讯

未完,待续…

lcd显示

未完,待续…

CAN通讯

未完,待续…

本文标签: 这一入门环境就够了IDF