W806-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 <stdio.h>
#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 main\r\n");
	
	//使用通道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 \r\n",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 %d\r\n", file, line);
}

程序中的ADC_Voltage_LSB表示实际电压和adc数值之间的线性系数 ADC_Voltage_LSB = 理论 / 实际adc读数。
这个系数是我多次测量得出来的结果。
第一列是万用表测出来PWM输出电压(PWM间隔10%,即0.33),第二列是ADC读出来的数值,第三列是理论上PWM的输出电压:当然这只是粗略值,看的出来也还行。
在这里插入图片描述

5、效果展示

电压是先变小再变大,然后再变小变大,依次循环。
在这里插入图片描述

版权声明:本文为CSDN博主「Mr·赵」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37280428/article/details/121518619

生成海报
点赞 0

Mr·赵

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

三相电机相电感,相电阻和极对数的测量

相电阻测量: 方法一:可使用万用表电阻档直接测量其中两端 方法二:可使用LCR数字电桥仪器测量 万用表操作: 将万用表旋转到电阻档的适当量程内 将万用表上的两表笔接触在电机的其中任意

数码管轮播显示

硬件: 数码管10个引脚,8个控制二极管亮、灭,2个引脚为负极。1k欧电阻链接负极,接gnd。 将8个二极管引脚依次链接0-7号引脚。 软件: /*共阳极单数码管显示&