本文基于:https://github.com/alibaba/AliOS-Things
ESP8266的PWM输出是基于Blink工程来完成的。
必须的组件:
使用ESP8266的SDK编程方法,偶然调通了!
没有文档,没有指导,只能从以前写的ESP8266 SDK PWM编程里面找灵感!如下是我以前写的PWM输出例程:
它的效果是,所有的PWM输出引脚输出占空比为0然后慢慢增加到100,占空比到100之后又缓慢递减到0的PWM波。循环往复。
#include "ets_sys.h"
#include "osapi.h"
#include "user_light.h"
#include "gpio.h"
#include "user_interface.h"
// 设置PWM通道:GPIO12、GPIO15、GPIO13、GPIO4、GPIO5(外加的)
#define PWM_0_OUT_IO_MUX PERIPHS_IO_MUX_MTDI_U
#define PWM_0_OUT_IO_NUM 12
#define PWM_0_OUT_IO_FUNC FUNC_GPIO12
#define PWM_1_OUT_IO_MUX PERIPHS_IO_MUX_MTDO_U
#define PWM_1_OUT_IO_NUM 15
#define PWM_1_OUT_IO_FUNC FUNC_GPIO15
#define PWM_2_OUT_IO_MUX PERIPHS_IO_MUX_MTCK_U
#define PWM_2_OUT_IO_NUM 13
#define PWM_2_OUT_IO_FUN CFUNC_GPIO13
#define PWM_3_OUT_IO_MUX PERIPHS_IO_MUX_GPIO4_U
#define PWM_3_OUT_IO_NUM 4
#define PWM_3_OUT_IO_FUNC FUNC_GPIO4
#define PWM_4_OUT_IO_MUX PERIPHS_IO_MUX_GPIO5_U
#define PWM_4_OUT_IO_NUM 5
#define PWM_4_OUT_IO_FUNC FUNC_GPIO5
#define PWM_CHANNEL 5 // 设置5个PWM通道
static os_timer_t os_timer;
/** 呼吸灯运行程序 */
void ESP8266_PWM_RUN( void )
{
/** PWM占空比变量 */
static u8 set_duty = 0;
/** 占空比加减标志 */
static bool f = true;
if ( f == true )
{
if ( ++set_duty >= 100 )
{
f = false;
}
}
else
{
if ( --set_duty <= 0 )
{
f = true;
}
}
/** 更新PWM通道0的占空比 */
pwm_set_duty( set_duty, 0 );
pwm_start();
}
/** 初始化PWM配置、系统定时器配置 */
void ESP8266_PWM_Init( void )
{
struct pwm_param pwm_config;
uint32_t io_info[ ][ 3 ] =
{
{PWM_0_OUT_IO_MUX,PWM_0_OUT_IO_FUNC,PWM_0_OUT_IO_NUM},
{PWM_1_OUT_IO_MUX,PWM_1_OUT_IO_FUNC,PWM_1_OUT_IO_NUM},
{PWM_2_OUT_IO_MUX,PWM_2_OUT_IO_FUNC,PWM_2_OUT_IO_NUM},
{PWM_3_OUT_IO_MUX,PWM_3_OUT_IO_FUNC,PWM_3_OUT_IO_NUM},
{PWM_4_OUT_IO_MUX,PWM_4_OUT_IO_FUNC,PWM_4_OUT_IO_NUM},
};
pwm_config.duty[ 0 ] = 0;
pwm_config.freq = 0;
pwm_config.period = 1000;
pwm_init( pwm_config.period, pwm_config.duty, PWM_CHANNEL , io_info );
/** 配置定时器每30ms执行一次ESP8266_PWM_RUN()函数 */
os_timer_disarm( &os_timer );
os_timer_setfn( &os_timer, (ETSTimerFunc *) ( ESP8266_PWM_RUN ), NULL );
os_timer_arm( &os_timer, 30, true );
}
/** 用户初始化程序,根据测试该程序只运行一次 */
void user_init(void)
{
ESP8266_PWM_Init();
}
想起,Blink例程中的LED闪烁那个操作的原理虽然不懂,但是效果和定时器的是一模一样的!所以,就以Blink例程为基础进行修改。
因为使用了ESP8266的资源所以需要在Blink.mk里面添加
Blink.mk
NAME := blink
$(NAME)_SOURCES := blink.c
$(NAME)_COMPONENTS += mcu/esp8266 # 添加ESP8266的资源
GLOBAL_DEFINES += AOS_NO_WIFI
$(NAME)_COMPONENTS := yloop cli
GLOBAL_INCLUDES += ./
为啥,是muc/esp8266
?因为,mcu的目录下没有.mk的文件,mcu的平级目录中也没有.mk文件,但是mcu目录下的子目录esp8266目录下是有.mk文件的。根据AliOS-Things的MK规则,现在esp8266下的所有资源都可以使用了。
修改一波之后,如下:
Blink.c
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include
#include
#include "stdio.h"
#include <../../../platform/mcu/esp8266/bsp/include/espressif/pwm.h>
#include <../../../platform/mcu/esp8266/bsp/include/driver/gpio.h>
/**
* Brief:
* This test code shows how to configure gpio and how to use gpio interrupt.
*
* GPIO status:
* GPIO18: output
* GPIO4: output
* GPIO5: input, pulled up, interrupt from rising edge and falling edge
*
* Test:
* Connect GPIO18 with LED
* Connect GPIO4 with GPIO5
* Generate pulses on GPIO4, that triggers interrupt on GPIO5 to blink the led.
*
*/
#define GPIO_LED_IO 13
#define GPIO_TRIGGER_IO 4
#define GPIO_INPUT_IO 5
// 暂时只使用0通道的PWM
#define PWM_0_OUT_IO_MUX PERIPHS_IO_MUX_MTDI_U
#define PWM_0_OUT_IO_NUM 12
#define PWM_0_OUT_IO_FUNC FUNC_GPIO12
// #define PWM_1_OUT_IO_MUX PERIPHS_IO_MUX_MTDO_U
// #define PWM_1_OUT_IO_NUM 15
// #define PWM_1_OUT_IO_FUNC FUNC_GPIO15
// #define PWM_2_OUT_IO_MUX PERIPHS_IO_MUX_MTCK_U
// #define PWM_2_OUT_IO_NUM 13
// #define PWM_2_OUT_IO_FUNC FUNC_GPIO13
// #define PWM_3_OUT_IO_MUX PERIPHS_IO_MUX_GPIO4_U
// #define PWM_3_OUT_IO_NUM 4
// #define PWM_3_OUT_IO_FUNC FUNC_GPIO4
// #define PWM_4_OUT_IO_MUX PERIPHS_IO_MUX_GPIO5_U
// #define PWM_4_OUT_IO_NUM 5
// #define PWM_4_OUT_IO_FUNC FUNC_GPIO5
#define PWM_CHANNEL 1 // 只使用了一个通道的PWM
static void app_trigger_low_action(void *arg);
static void app_trigger_high_action(void *arg);
gpio_dev_t led;
gpio_dev_t trigger;
gpio_dev_t input;
static void gpio_isr_handler(void* arg)
{
uint32_t gpio_num = (uint32_t) arg;
uint32_t value = 0;
hal_gpio_input_get(&input, &value);
hal_gpio_output_toggle(&led);
LOG("GPIO[%d] intr, val: %d\n", gpio_num, value);
}
/** 呼吸灯运行程序 */
void ESP8266_PWM_RUN( void )
{
/** PWM占空比变量 */
static u8 set_duty = 0;
/** 占空比加减标志 */
static bool f = true;
if ( f == true )
{
if ( ++set_duty >= 100 )
{
f = false;
}
}
else
{
if ( --set_duty <= 0 )
{
f = true;
}
}
/** 更新PWM通道0的占空比 */
printf("set_duty>>>%d\r\n", set_duty);
pwm_set_duty( set_duty, 0 );
pwm_start();
}
static void app_trigger_low_action(void *arg)
{
hal_gpio_output_low(&trigger);
aos_post_delayed_action(100, app_trigger_high_action, NULL);
ESP8266_PWM_RUN(); // 放到这里,如同定时器的效果一样。
}
static void app_trigger_high_action(void *arg)
{
hal_gpio_output_high(&trigger);
aos_post_delayed_action(100, app_trigger_low_action, NULL);
}
/** 初始化PWM配置、系统定时器配置 */
void ESP8266_PWM_Init( void )
{
struct pwm_param pwm_config_t;
uint32_t io_info[ ][ 3 ]={
{PWM_0_OUT_IO_MUX,PWM_0_OUT_IO_FUNC,PWM_0_OUT_IO_NUM},
// {PWM_1_OUT_IO_MUX,PWM_1_OUT_IO_FUNC,PWM_1_OUT_IO_NUM},
// {PWM_2_OUT_IO_MUX,PWM_2_OUT_IO_FUNC,PWM_2_OUT_IO_NUM},
// {PWM_3_OUT_IO_MUX,PWM_3_OUT_IO_FUNC,PWM_3_OUT_IO_NUM},
// {PWM_4_OUT_IO_MUX,PWM_4_OUT_IO_FUNC,PWM_4_OUT_IO_NUM},
};
pwm_config_t.duty[ 0 ] = 0;
pwm_config_t.freq = 0;
pwm_config_t.period = 100;
pwm_init( pwm_config_t.period, pwm_config_t.duty, PWM_CHANNEL, io_info );
/** 配置定时器每30ms执行一次ESP8266_PWM_RUN()函数 */
// os_timer_disarm( &os_timer );
// os_timer_setfn( &os_timer, (ETSTimerFunc *) ( ESP8266_PWM_RUN ), NULL );
// os_timer_arm( &os_timer, 30, true );
}
int application_start(int argc, char *argv[])
{
ESP8266_PWM_Init(); // PWM 初始化
/* gpio port config */
led.port = GPIO_LED_IO;
/* set as output mode */
led.config = OUTPUT_PUSH_PULL;
/* configure GPIO with the given settings */
hal_gpio_init(&led);
/* gpio port config */
trigger.port = GPIO_TRIGGER_IO;
/* set as output mode */
trigger.config = OUTPUT_PUSH_PULL;
/* configure GPIO with the given settings */
hal_gpio_init(&trigger);
/* input pin config */
input.port = GPIO_INPUT_IO;
/* set as interrupt mode */
input.config = IRQ_MODE;
/* configure GPIO with the given settings */
hal_gpio_init(&input);
/* gpio interrupt config */
hal_gpio_enable_irq(&input, IRQ_TRIGGER_BOTH_EDGES, gpio_isr_handler, (void *) GPIO_INPUT_IO);
aos_post_delayed_action(1000, app_trigger_low_action, NULL);
aos_loop_run();
return 0;
}
1、PERIPHS_IO_MUX_MTDI_U
这个找不到,没定义(贼多错误,满屏都是)。。。。
解决办法:在路径:AliOS-Things-master\AliOS-Things-master\platform\mcu\esp8266\bsp\include\driver\gpio.h这个地方在gpio.h里面添加如下包含头文件,即可搞定:
#ifndef __GPIO_H__
#define __GPIO_H__
#ifdef __cplusplus
extern "C" {
#endif
/****开始复制****/
#include "c_types.h"
#include "../espressif/esp8266/gpio_register.h"
#include "../espressif/esp8266/pin_mux_register.h"
/*****结束复制****/
#define GPIO_Pin_0 (BIT(0)) /* Pin 0 selected */
编译:aos make blink@esp8266
搞定!下载程序之后就可以看到效果了! 注意是引脚是:GPIO12
在路径这里系统自带了三个文件:AliOS-Things-master\AliOS-Things-master\platform\mcu\esp8266,需要同时下载到ESP8266里面去,具体地址配置下面有截图。
对应地址:
文件名 | 下载地址 |
---|---|
blank.bin | 0xFE000 |
esp_init_data_default.bin | 0xFC000 |
boot_v1.7.bin | 0x00000 |
blink@esp8266 | 0x01000 |
在目录这里:AliOS-Things-master\AliOS-Things-master\out\blink@esp8266\binary有编译出来的主文件。
其实,不用那个定时器的效果也是可以的,就如下面这样写,pwm初始化之后就固定输出一个PWM波:
/** 初始化PWM配置、系统定时器配置 */
void ESP8266_PWM_Init( void )
{
struct pwm_param pwm_config_t;
uint32_t io_info[ ][ 3 ]={
{PWM_0_OUT_IO_MUX,PWM_0_OUT_IO_FUNC,PWM_0_OUT_IO_NUM},
};
pwm_config_t.duty[ 0 ] = 0;
pwm_config_t.freq = 0;
pwm_config_t.period = 100;
pwm_init( pwm_config_t.period, pwm_config_t.duty, PWM_CHANNEL, io_info );
// 输出一个固定的PWM波
pwm_set_duty(80, 0 );
pwm_start();
}
然后还做了一系列的测试:
period(配置) | duty(配置) | 频率(实际输出) | 周期(实际输出) | 高脉冲 | 低脉冲 |
---|---|---|---|---|---|
50 | 80 | 19.16KHz | 51us | 50us | 1us |
100 | 80 | 10KHz | 100us | 80us | 20us |
200 | 80 | 5KHz | 200us | 80us | 120us |
300 | 80 | 3.33KHz | 300us | 80us | 220us |
经过比较, pwm_config_t.period = 100;
是最好的配置参数。