W806-ADC-PWM-TIM尝鲜

发布者:TranquilWhisper最新更新时间:2022-07-26 来源: csdn关键字:ADC  PWM  TIM 手机看文章 扫描二维码
随时随地手机看文章

本文使用环境:

电脑:windows10

主控:W806(240MHZ)

编译环境:平头哥的CDK

注意:本文默认已经搭建好平台。


前言

写这篇问章的目的是记录一下自己的ADC使用路程,前期这个ADC我是一直没有看明白,后面才搞的是懂非懂。

当然本文肯定不止使用ADC,那样显得没有技术水平,SO,为了提升技术难度,在adc的基础上加了一点点东西:

使用PB0产生100KHZ动态变化的的PWM,然后由PA1的ADC获取到,并转化成实际的电压。B0产生的PWM通过不断的改变比较值可以输出不同的电压,所以就能够满足ADC的采集要求,这里需要注意的是,不能直接测量电源电压,要不然要烧。。。。。

完整程序下载:

https://download.csdn.net/download/qq_37280428/48278788


一、编程

1. ADC编程

官方也有ADC的demo,所以这里主要说一下ADC的初始化以及,值读取出来后如何转化成实际的电压值。

具体的参考官方程序,


1.1、查端口

要编程之前我们首先要确定使用的外设IO,所以第一步打开官方数据手册,看看哪些口是可以使用的,打开如下文档。

在这里插入图片描述

直接ctrl+F,可以发现这个编号是非常奇怪的。

在这里插入图片描述

我们使用A1即可,默认也是A0所以问题不大,同时我们看一下文档中关于ADC的章节。

在这里插入图片描述

明确说明了,ADC最多只能是2.4V,所以,这就是之前说的不能直接接电源电压。。。。。。


同时查看ADC的参数信息(W806 MCU 芯片规格书 V2.0):这参数一般般

在这里插入图片描述

2、PWM编程

2.1、查手册

首先查手册,设计指导书和规格书都可以查,发现有很多的IO都是可以选择的,这里选择B0,PWM0。

在这里插入图片描述

除此之外,我们还需要打开一个手册:

在这里插入图片描述

翻到如下章节:

在这里插入图片描述

PWM时钟频率是3-160KHz,这都是后续需要设置的地方。


2.2、PWM编程

PWM的初始化需要特别注意,如果单独使用PWM0,使用官方的教程没有问题,但是如果你想使用 多路PWM,并且需要每一路单独输出PWM,就需要对PWM的初始化做修改。官方的初始化如下:(这个初始化不能完成每一路PWM单独输出)


static void PWM_Init(void)

{

// 输出100KHz、占空比40%的波形

hpwm.Instance = PWM;

hpwm.Init.AutoReloadPreload = PWM_AUTORELOAD_PRELOAD_ENABLE;

hpwm.Init.CounterMode = PWM_COUNTERMODE_EDGEALIGNED_DOWN;

hpwm.Init.Prescaler = 4;

hpwm.Init.Period = 99; // 40M / 4 / 100K - 1

hpwm.Init.Pulse = 0; // 0% DUTY

hpwm.Init.OutMode = PWM_OUT_MODE_5SYNC;

hpwm.Channel = ch;

HAL_PWM_Init(&hpwm);

}


其中Pulse 表示占空比,such as:Pulse 设置成0 就表示低电平,设置成Period /2就表示50%的占空比,设置成Period 就表示高电平,中间的就是高电平和低电平之比。动态改变这个值就可以输出可占空比波形。特别需要注意的是,由于ADC的输入电压不能高于2.4V所以,这里我做了限幅,在下面的完整程序中有设置,为什么是70? 3.3*0.7 = 2.31V 满足要求。


#define adc_max  70


同时这里需要注意两个点:

1、频率设置

系统默认输出的是100K的信号,那问题来了 这100K是如何设置的呢???

经过我的不断尝试,我发现,PWM的时钟输入默认是40MHz,所以这里直接按照40MHz,计算。这里直接给公式,自己去算。


输出频率 khz = 40000kHZ/4(分频系数)/(Period+1)


2、输出模式

观察上述代码的OutMode 设置的是PWM_OUT_MODE_5SYNC,字面意思,5通道同步模式,也就是说,每个通道输出的PWM都是一样的,如果单独输出需要修改为独立模式。按住ctrl然后单击PWM_OUT_MODE_5SYNC,即可跳转到宏定义的地方:


// PWM_Out_Mode

#define PWM_OUT_MODE_INDEPENDENT 0x00

#define PWM_OUT_MODE_2SYNC 0x01

#define PWM_OUT_MODE_2COMPLEMENTARY 0x02

#define PWM_OUT_MODE_5SYNC 0x03

#define PWM_OUT_MODE_BREAK 0x04


这是五种不同的模式,第一种就是独立,所以有需要单独使用没一路PWM的,可以直接改成第一种。


static void PWM_Init(void)

{

// 输出100KHz、占空比40%的波形

hpwm.Instance = PWM;

hpwm.Init.AutoReloadPreload = PWM_AUTORELOAD_PRELOAD_ENABLE;

hpwm.Init.CounterMode = PWM_COUNTERMODE_EDGEALIGNED_DOWN;

hpwm.Init.Prescaler = 4;

hpwm.Init.Period = 99; // 40M / 4 / 100K - 1

hpwm.Init.Pulse = 0; // 0% DUTY

hpwm.Init.OutMode = PWM_OUT_MODE_INDEPENDENT;  //独立通道输出

hpwm.Channel = ch;

HAL_PWM_Init(&hpwm);

}


其他的完全按照教程走就可以了。


3、TIM编程

3.1、编程

这个编程不再赘述,按照官方demo出来就行。本文设置成==1000000US。==每1S改变一次PWM的值,改变一次输出电压。


4、 完整程序及计算方式

话不多说直接上程序。

#include

#include "wm_hal.h"


#define ADC_Voltage_LSB 0.0013

#define adc_max  70  //PWM输出的最大值,按照周期100来算的。3.3*0.7 = 2.31


void Error_Handler(void);

//ADC INIT

static void ADC_Init(void);

ADC_HandleTypeDef hadc;


//PWM init

PWM_HandleTypeDef hpwm;

static void PWM_Init(void);

void Error_Handler(void);

uint32_t ch = PWM_CHANNEL_0;


//TIME init

TIM_HandleTypeDef htim0;

static void TIM0_Init(void);


int main(void)

{

SystemClock_Config(CPU_CLK_240M);

printf("enter mainrn");

//使用通道0  B0

PWM_Init();

HAL_PWM_Start(&hpwm, ch);

//使用通道0 A0

ADC_Init();

//定时器 TIME0

TIM0_Init();

//在wm_it.c文件中,需要修改对应的参数

HAL_TIM_Base_Start_IT(&htim0);

while (1)

{

;

}

}


static void TIM0_Init(void)

{

htim0.Instance = TIM0;

htim0.Init.Unit = TIM_UNIT_US;

htim0.Init.Period = 1000000;  //1s

htim0.Init.AutoReload = TIM_AUTORELOAD_PRELOAD_ENABLE;

if (HAL_TIM_Base_Init(&htim0) != HAL_OK)

{

Error_Handler();

}

}


/* 输出波形的频率: f = 40MHz / Prescaler / (Period + 1);

 * 输出波形的占空比: 

 *     沿对齐模式(递减):(Pulse + 1) / (Period + 1)

 *                         Pulse >= Period:PWM输出一直为高电平

 *                         Pulse < Period :PWM输出高电平宽度为(Pulse + 1),低电平宽度为(Period - Pulse)

 *                         Pulse = 0      :PWM输出高电平宽度为(1),低电平宽度为(Period)

 * 

 *    中间对齐模式       :(2 * Pulse + 1) / (2 * (Period + 1))

 *                         Pulse > Period :PWM输出一直为高电平

 *                         Pulse <= Period:PWM输出高电平宽度为(2 * Pulse + 1),低电平宽度为(2 * (Period - Pulse) + 1)

 *                         Pulse = 0      :PWM输出高电平宽度为(1),低电平宽度为(2 * Period + 1)

 */

static void PWM_Init(void)

{

// 输出100KHz、占空比40%的波形

hpwm.Instance = PWM;

hpwm.Init.AutoReloadPreload = PWM_AUTORELOAD_PRELOAD_ENABLE;

hpwm.Init.CounterMode = PWM_COUNTERMODE_EDGEALIGNED_DOWN;

hpwm.Init.Prescaler = 4;

hpwm.Init.Period = 99; // 40M / 4 / 100K - 1

hpwm.Init.Pulse = 0; // 0% DUTY

hpwm.Init.OutMode = PWM_OUT_MODE_5SYNC;

hpwm.Channel = ch;

HAL_PWM_Init(&hpwm);

}

//1K的频率

static void ADC_Init(void)

{

hadc.Instance = ADC;

hadc.Init.channel = ADC_CHANNEL_0;

hadc.Init.freq = 1000;

if (HAL_ADC_Init(&hadc) != HAL_OK)

{

Error_Handler();

}

}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)

{}


//可以理解成定时器服务函数

//1S

void HAL_TIM_Callback(TIM_HandleTypeDef *htim)

{

static int8_t adc_num = 1;

static bool adc_flage = 1;

if (htim->Instance == TIM0)

{

if(adc_num > adc_max ||adc_num <= 0)

adc_flage = !adc_flage;

if(0 == adc_flage)

adc_num++;

else

adc_num--;

HAL_PWM_Duty_Set(&hpwm, PWM_CHANNEL_0, adc_num);

int16_t value_2 = HAL_ADC_GET_INPUT_VOLTAGE(&hadc) - 14;  //14ADC是对地测量值,这个值需要根据实际情况进行测量,我的板子是这么多,不代表你的板子也是。

//这一步是防止减出来是负值,会出错的

if(0 >= value_2)

value_2 = 0;

float V_actural = value_2*ADC_Voltage_LSB;  //ADC_Voltage_LSB 表示实际电压和ADC数值之间的关系,还是比较线性的。

  printf("  %d   %0.2fV rn",value_2,V_actural);

}

}


void Error_Handler(void)

{

while (1)

{

}

}


void assert_failed(uint8_t *file, uint32_t line)

{

printf("Wrong parameters value: file %s on line %drn", file, line);

}


程序中的ADC_Voltage_LSB表示实际电压和adc数值之间的线性系数 ADC_Voltage_LSB = 理论 / 实际adc读数。

这个系数是我多次测量得出来的结果。

第一列是万用表测出来PWM输出电压(PWM间隔10%,即0.33),第二列是ADC读出来的数值,第三列是理论上PWM的输出电压:当然这只是粗略值,看的出来也还行。

在这里插入图片描述

5、效果展示

电压是先变小再变大,然后再变小变大,依次循环。

在这里插入图片描述

关键字:ADC  PWM  TIM 引用地址:W806-ADC-PWM-TIM尝鲜

上一篇:W801/W800蓝牙收发数据与控制设计(一)-INDICATE
下一篇:联盛德W806+INA226 = 功率计

推荐阅读最新更新时间:2024-11-10 09:20

STM8S的按键PWM调光灯历程
STM8SPWM应用 前几天有个项目用到PWM,今天整理下,弄个氛围灯;记录下,以后忘记了返回来还能看看。 思路就是在硬件端设置个按键,按下全局变量Key_num的值+1,按键一开始我用轮询法做的,后来觉得轮询法延时可能导致未知的问题,现在用中断法做;根据Key_num的值,用switch语句选择要变换的模样。 上代码: /***************************************************************************** * @function : Tim2_Init * @brief : TIM2初始化函数 CH1用作出LED——G的呼吸变化灯 *
[单片机]
有高精度绝对读数的低成本旋转编码器
旋转 编码器 通常用于带伺服反馈的定位系统,这种情况下,编码器的成本一般并不重要。但编码器也会用于对某些用户界面上旋钮位置的编码,例如 音频系统 上的音量旋钮。对于这些旋钮,可以为求低价、高精度和绝对读数值而选择 电位器 ,但它们行程有限,通常不到340°,或者可选择光机式旋转编码器,它的行程没有限制,但价格较高,精度低,只有相对读数值。本设计实例尝试将两者结合起来,兼具了电位器的优点,以及光机旋转编码器无边界操作的特性。 编码器采用了标准电位器的结构技术,因此便于生产。它基本上是一个双电刷正交式无界电位器。它有一个全圆的阻性材料环,两端接电,两个电气独立的刷片在上面移动。两电刷片相互间为90°角的机械连接(图1)。 微
[嵌入式]
详述ADC精度和分辨率的概念差异
在与使用模数转换器 (ADC) 的系统设计人员进行交谈时,我最常听到的一个问题就是: 你的16位ADC的精度也是16位的吗? 这个问题的答案取决于对分辨率和精度概念的基本理解。尽管是两个完全不同的概念,这两个数据项经常被搞混和交换使用。 该文详述了这两个概念间的差异,并将深入研究造成ADC不准确的主要原因。 ADC的分辨率被定义为输入信号值的最小变化,这个最小数值变化会改变数字输出值的一个数值。对于一个理想ADC来说,传递函数是一个步宽等于分辨率的阶梯。然而,在具有较高分辨率的系统中( 16位),传输函数的响应将相对于理想响应有一个较大的偏离。这是因为ADC以及驱动器电路导致的噪声会降低ADC的分辨率。 此外,如果DC电
[电源管理]
详述<font color='red'>ADC</font>精度和分辨率的概念差异
NO.16 PWM的概念以及MSP432中如何调用
  什么是PWM?它全称是脉冲宽度调制,是一种模拟控制方式。   具体是什么意思呢?PWM跟我们的定时器紧密联系在一起。   假设我们有一盏灯,对于灯来说。在某一时刻中只有一种情况,开或者关,即1或者0。如果我们控制灯1s开,1s关,你会看到灯在闪烁,如果我们控制灯0.1s开,0.1s关,你会看到灯的闪烁频率变大了。那我们控制灯0.001s开,0.001关呢?那么我们的人眼由于视觉暂留的因素,将不会看到灯的闪烁,反而我们会看到灯的亮度降低了一半。原来1个单位亮度的,现在只有0.5个单位亮度。那我们继续假设。假设我们的控制时间趋近于无穷小,那我们根本不会看到灯的闪烁。这就是PWM控制的思想。本来我们只有0和1两个数,进行PW
[单片机]
STM8单片机 PWM无波形输出解决方法
  调试STM8单片机PWM功能的时候,经常会遇到一种情况,就是PWM初始化设置完成之后,程序下载到单片机中,确没有任何波形的输出。有时候代码是下载别的调试好的,但是在自己芯片上就是没有波形输出。这时要么骂双穿代码的人忽悠人,上传的代码是错的,要么怀疑自己的单片机坏了。   现在就来分析一下,命名代码正确,但是确没有波形输出这种情况要如何分析判断。   首先来看一下PWM的初始化代码 void TIM1_Init( void ) { TIM1_CCMR2 = 0x60; //TIM1 CH2 输出模式 PWM1 TIM1_CCER1 |= 0x10; //CC2为输出 TIM1_PSCRH
[单片机]
STM8单片机 <font color='red'>PWM</font>无波形输出解决方法
怎样采用多种单端信号驱动低功率的16 位ADC
匹配传感器输出和 ADC 输入范围可能很难,尤其是要面对当今传感器所产生的多种输出电压摆幅时。本文为不同变化范围的差分、单端、单极性和双极性信号提供简便但高性能的 ADC 输入驱动器解决方案,本文的所有电路採用了 LTC2383-16 ADC 单独工作或与 LT6350 ADC 驱动器一起工作来实现 92dB SNR。   LTC2383-16 是一款低噪声、低功率、1Msps、16 位 ADC,具备 ±2.5V 的全差分输入范围。LT6350 是一款轨至轨输入和输出的、低噪声、低功率单端至差分转换器/ADC 驱动器,具备快速稳定时间。运用 LT6350,0V 至 2.5V、0V 至 5V 和 ±10V 的单端输入范围可以很容易
[模拟电子]
怎样采用多种单端信号驱动低功率的16 位<font color='red'>ADC</font>
技术文章—如何将PWM信号转换为模拟量信号
有一个测量位置变化的位置传感器,用万用表电压档测量传感器的输出信号,结果显示的是模拟量信号,即位置和信号输出大小呈线性关系。但是,用示波器(Picoscope 4227)测量传感器的输出信号,显示的却是PWM信号(脉宽调制),即位置不同,输出PWM信号的占空比不同。 PWM信号的参数是:200 Hz, 低电平为0V,高电平为18V。 现在可以确定,我的传感器输出信号是PWM信号。PWM信号需要输入到控制器I/O中,但是控制器I/O口不具备直接采集PWM信号的功能。 解决方案 设计个电路,将PWM信号转化为模拟量信号,然后将转换后的模拟量信号输入到控制器模拟量I/O口。 转换电路
[测试测量]
技术文章—如何将<font color='red'>PWM</font>信号转换为模拟量信号
MSP430 ADC12(一)
以下代码运行ADC12模块,P6.0为输入通道,P1.0为输出。当输入电压大于0.5电源电压VCC时点亮LED。 注意:__even_in_range(ADC12IV,34) 是判断ADC12IV是否为0-34之间的偶数,如果是执行switch语句,此做法是为了提高switch语句的执行效率,用于多中断来源判断。 #include msp430.h int main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT ADC12CTL0 = ADC12SHT02 + ADC12ON; // 采样时间,打开ADC12 ADC12CTL1 = ADC12
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved