打印

adc采样控制pwm的问题

[复制链接]
6140|42
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
djz1992|  楼主 | 2015-12-29 09:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我现在需要的功能是:在某一时间后,采样电压,然后超过目标值就驱动电机调压,到了目标值就停止,如果小于目标值就反向调压。
我用的TI的TIVA系列单片机,ADC采样和PWM输出我都可以实现,但是联动起来就有些问题。
TI的函数里都是unsigned int32 定义的变量,我用采样值减去目标值得到一个差值,利用差值的正负、大小,判断是否需要调压,因为有三相,所以for循环三次
遇到了几个问题
1.无法反转和停止,差值恒大于128,我想应该是无符号数不会小于0的错误,但是我如果count定义成有符号的,TI的函数里ADC0_Value是个无符号数,貌似没法相减得到有符号数。可以吗?
2.恒为高电平的PWM总是参杂着很短时间的低电平,我想是不是采样值在临界值左右时刻变化,导致的pwm时开时关。但是我调节电压,低电平一直存在。鉴于第一个问题,无法实现电压变化控制PWM的通断,低电平一直存在倒也不能说明什么。
3.不知道要实现这个功能,该用什么方式避免采样波动引起的边界问题?
for(a=0;a<3;a++)
        {
                count=ADC0_Value[a]-goal;
                PWM_CTRL(count,a);
        }//把三相电压ADC0、ADC1、ADC2和目标值的差值计算出来
        a=0;


void PWM_CTRL(uint32_t count,uint8_t a)//控制三相电机的启动、停止、正反转
{
        if(a==0)
        {
                if(count>=128)
                {S0=4800;S1=0; PWMOutputState(PWM0_BASE, (PWM_OUT_0_BIT |PWM_OUT_1_BIT), true);}//正转
                else if(0<count<128)
                {PWMOutputState(PWM0_BASE, (PWM_OUT_0_BIT |PWM_OUT_1_BIT), false);}//不转
                else
                {S0=0;S1=4800; PWMOutputState(PWM0_BASE, (PWM_OUT_0_BIT |PWM_OUT_1_BIT), true);}//反转
        }
        if(a==1)
        {
                if(count>=128)
                {S2=4800;S3=0; PWMOutputState(PWM0_BASE, (PWM_OUT_2_BIT |PWM_OUT_3_BIT), true);}//正转
                else if(0<count<128)
                {PWMOutputState(PWM0_BASE, (PWM_OUT_2_BIT |PWM_OUT_3_BIT), false);}//不转
                else
                {S2=0;S3=4800; PWMOutputState(PWM0_BASE, (PWM_OUT_2_BIT |PWM_OUT_3_BIT), true);}//反转
        }
        if(a==2)
        {
                if(count>=128)
                {S4=4800;S5=0; PWMOutputState(PWM0_BASE, (PWM_OUT_4_BIT |PWM_OUT_5_BIT), true);}//正转
                else if(0<count<128)
                {PWMOutputState(PWM0_BASE, (PWM_OUT_4_BIT |PWM_OUT_5_BIT), false);}//不转
                else
                {S4=0;S5=4800; PWMOutputState(PWM0_BASE, (PWM_OUT_4_BIT |PWM_OUT_5_BIT), true);}//反转
        }
}

相关帖子

沙发
dirtwillfly| | 2015-12-29 10:10 | 只看该作者
1、可以先比较大小,然后再做减计算

使用特权

评论回复
板凳
dirtwillfly| | 2015-12-29 10:11 | 只看该作者
pwm是矩型波,肯定有高低电平变化的

使用特权

评论回复
地板
dirtwillfly| | 2015-12-29 10:13 | 只看该作者
3、一般采样不会引起电压波动的,不清楚你的电路是呢么样的。建议提供下电路图和相关的波形截图

使用特权

评论回复
5
djz1992|  楼主 | 2015-12-29 11:12 | 只看该作者
dirtwillfly 发表于 2015-12-29 10:13
3、一般采样不会引起电压波动的,不清楚你的电路是呢么样的。建议提供下电路图和相关的波形截图 ...

采样电路的话就是很简单的电阻分压,然后降到3.3V以内,直接连到单片机引脚。我在调试launchpad时候,用函数信号发生器输出1.65V的电压,看程序内的ADCvalue的值,一会儿2000,再循环一个又1300。。感觉波动很大啊。不知道什么原因。
我本要采样6路,但是函数信号发生器只给了PE3一个脚信号,但是我在观察保存采样值的value【6】时发现,value【0】=2000,其余value【1】、value【2】等等都有值,而且都很大,都有两三千。那些引脚我并没有接信号,为什么还会采到电压。我用示波器查看那几个引脚的电压,发现确实有1.65V左右的电压,不知道为什么

使用特权

评论回复
6
dirtwillfly| | 2015-12-29 11:19 | 只看该作者
djz1992 发表于 2015-12-29 11:12
采样电路的话就是很简单的电阻分压,然后降到3.3V以内,直接连到单片机引脚。我在调试launchpad时候,用 ...

1、adc采样值除了和信号电压有关,还和你选择的基准电压有关系,如果你选择vcc作为基准电压,随着vcc的电压波动,采样值就会变。另外,还和干扰、阻抗等情况有关

使用特权

评论回复
7
dirtwillfly| | 2015-12-29 11:20 | 只看该作者
2、未连接的io,一般都是悬空状态,会有感应电压存在,采样值随感应电压变化

使用特权

评论回复
8
djz1992|  楼主 | 2015-12-29 12:28 | 只看该作者
dirtwillfly 发表于 2015-12-29 11:20
2、未连接的io,一般都是悬空状态,会有感应电压存在,采样值随感应电压变化 ...

那您建议如何提高采样精度呢?多次采样取平均么

使用特权

评论回复
9
dirtwillfly| | 2015-12-29 12:34 | 只看该作者
djz1992 发表于 2015-12-29 12:28
那您建议如何提高采样精度呢?多次采样取平均么


没看到你的电路,不清楚具体什么原因导致的采样不稳。要找出具体原因,有针对地采取措施

使用特权

评论回复
10
djz1992|  楼主 | 2015-12-29 12:42 | 只看该作者
dirtwillfly 发表于 2015-12-29 12:34
没看到你的电路,不清楚具体什么原因导致的采样不稳。要找出具体原因,有针对地采取措施 ...

就是直接从函数信号发生器接到PE3,ADC0上,中间没有任何电路

使用特权

评论回复
11
dirtwillfly| | 2015-12-29 12:46 | 只看该作者
djz1992 发表于 2015-12-29 12:42
就是直接从函数信号发生器接到PE3,ADC0上,中间没有任何电路

PE3脚采样值是多少啊?波动也很大吗?

使用特权

评论回复
12
djz1992|  楼主 | 2015-12-29 12:53 | 只看该作者
dirtwillfly 发表于 2015-12-29 12:46
PE3脚采样值是多少啊?波动也很大吗?

对啊  一直接的1.65V  照理说应该是2048,采到的是1900,再运行一遍又变成1200,差的很多

使用特权

评论回复
13
dirtwillfly| | 2015-12-29 13:00 | 只看该作者
djz1992 发表于 2015-12-29 12:53
对啊  一直接的1.65V  照理说应该是2048,采到的是1900,再运行一遍又变成1200,差的很多 ...

有可能adc配置不有问题,方便的话建议把代码传上来

使用特权

评论回复
14
djz1992|  楼主 | 2015-12-29 13:03 | 只看该作者
//模数转换器实验程序解析
//头文件
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "inc/hw_gpio.h"
#include "driverlib/fpu.h"
#include "driverlib/sysctl.h"
#include "driverlib/rom.h"
#include "driverlib/pin_map.h"
#include "grlib/grlib.h"
#include "driverlib/gpio.h"
#include "driverlib/adc.h"
#include "driverlib/pwm.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"
#include "driverlib/interrupt.h"

uint32_t S0=0,S1=0,S2=0,S3=0,S4=0,S5=0;
uint32_t ADC0_Value[6],Data[6]={0},goal[3];
uint32_t count;

void PWM_INIT(void)
{
        //使能M0PWM模块
        SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0);
        //使能M0PWM0和M0PWM1输出所在GPIOB和GPIOG
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
       
        //配置相应GPIO为PWM功能
        GPIOPinTypePWM(GPIO_PORTB_BASE, GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_4|GPIO_PIN_5);
        GPIOPinTypePWM(GPIO_PORTE_BASE, GPIO_PIN_5|GPIO_PIN_4);//不同:PG4、PG5
        // PWM时钟配置:不分频
        SysCtlPWMClockSet(SYSCTL_PWMDIV_1);
        //配置M0PWM发生器:加减计数
        PWMGenConfigure(PWM0_BASE,PWM_GEN_0,PWM_GEN_MODE_UP_DOWN| PWM_GEN_MODE_NO_SYNC);
        //设置M0PWM发生器的周期,时钟频率/PWM分频数/n,周期=80M/1/6000=
        PWMGenPeriodSet(PWM0_BASE, PWM_GEN_0, 6000);
        PWMGenPeriodSet(PWM0_BASE, PWM_GEN_1, 6000);
        PWMGenPeriodSet(PWM0_BASE, PWM_GEN_2, 6000);
        //设置M0PWM0/M0PWM1输出的脉冲宽度
        PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0, S0);//此处S0+S1<=6000
        PWMPulseWidthSet(PWM0_BASE, PWM_OUT_1, S1);
        PWMPulseWidthSet(PWM0_BASE, PWM_OUT_2, S2);
        PWMPulseWidthSet(PWM0_BASE, PWM_OUT_3, S3);
        PWMPulseWidthSet(PWM0_BASE, PWM_OUT_5, S4);
        PWMPulseWidthSet(PWM0_BASE, PWM_OUT_4, S5);
        //使能M0PWM0和M0PWM1的输出
        //PWMOutputState(PWM0_BASE, (PWM_OUT_0_BIT |PWM_OUT_1_BIT), true);
        //PWMOutputState(PWM0_BASE, (PWM_OUT_2_BIT |PWM_OUT_3_BIT), true);
        //PWMOutputState(PWM0_BASE, (PWM_OUT_4_BIT |PWM_OUT_5_BIT), true);
        //使能M0PWM发生器生成模块0
        PWMGenEnable(PWM0_BASE, PWM_GEN_0);
        PWMGenEnable(PWM0_BASE, PWM_GEN_1);
        PWMGenEnable(PWM0_BASE, PWM_GEN_2);
}

void PWM_CTRL(uint32_t count,uint8_t a)//控制三相电机的启动、停止、正反转
{
        if(a==0)
        {
                if(count>=128)
                {S0=4800;S1=0;PWMOutputState(PWM0_BASE, (PWM_OUT_0_BIT |PWM_OUT_1_BIT), true);}//正转
                else if(0<count<128)
                {PWMOutputState(PWM0_BASE, (PWM_OUT_0_BIT |PWM_OUT_1_BIT), false);}//不转
                else
                {S0=0;S1=4800;PWMOutputState(PWM0_BASE, (PWM_OUT_0_BIT |PWM_OUT_1_BIT), true);}//反转
        }
        if(a==1)
        {
                if(count>=128)
                {S2=4800;S3=0;PWMOutputState(PWM0_BASE, (PWM_OUT_2_BIT |PWM_OUT_3_BIT), true);}//正转
                else if(0<count<128)
                {PWMOutputState(PWM0_BASE, (PWM_OUT_2_BIT |PWM_OUT_3_BIT), false);}//不转
                else
                {S2=0;S3=4800;PWMOutputState(PWM0_BASE, (PWM_OUT_2_BIT |PWM_OUT_3_BIT), true);}//反转
        }
        if(a==2)
        {
                if(count>=128)
                {S4=4800;S5=0;PWMOutputState(PWM0_BASE, (PWM_OUT_4_BIT |PWM_OUT_5_BIT), true);}//正转
                else if(0<count<128)
                {PWMOutputState(PWM0_BASE, (PWM_OUT_4_BIT |PWM_OUT_5_BIT), false);}//不转
                else
                {S4=0;S5=4800;PWMOutputState(PWM0_BASE, (PWM_OUT_4_BIT |PWM_OUT_5_BIT), true);}//反转
        }
}

void ADC_INIT(void)
{
        //初始化ADC0/PE3
        //SysCtlADCSpeedSet(SYSCTL_ADCSPEED_500KSPS);//设置采样速度,默认1MHZ
        SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
        GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
        GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);

        //设置ADC参考电压为外部3V,TM4C123GH6PM只能使用内部参考电压,3.3V
        //ADCReferenceSet(ADC0_BASE, ADC_REF_EXT_3V);//若ADC_REF_INT,则指使用内部3V参考电压
        //配置ADC采集序列
        ADCSequenceConfigure(ADC0_BASE, 0,ADC_TRIGGER_PROCESSOR, 0);
        ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0 );//PE3
        ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH1 );//PE2
        ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH2 );//PE1
        ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH3 );//PE0
        ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH4 );//PD3
        ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH5 );//PD2
        ADCSequenceStepConfigure(ADC0_BASE, 0, 6, ADC_CTL_CH6 | ADC_CTL_IE |ADC_CTL_END);//PD1
        //ADCSequenceStepConfigure(ADC0_BASE, 0, 7, ADC_CTL_CH7 | ADC_CTL_IE |ADC_CTL_END);//PD0未使用

        //使能ADC采集序列
        ADCSequenceEnable(ADC0_BASE, 0);
        //IntEnable(INT_ADC0SS0);
        IntMasterEnable();
        ADCIntEnable(ADC0_BASE, 0);
        //ADCIntEnableEx(ADC0_BASE,ADC_INT_DMA_SS0);//中断触发设置
        ADCIntClear(ADC0_BASE, 0);
}

int main(void)
{
        uint8_t a=0,b=0;
        //使能FPU
        FPUEnable();
        FPULazyStackingEnable();
        //设置系统时钟为50MHz (400/2/4=50)
        SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL |SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);
        UATR_INIT();
        ADC_INIT();
        PWM_INIT();
while(1)
{
        //触发采集
        ADCProcessorTrigger(ADC0_BASE, 0);
        //等待采集结束
        while(!ADCIntStatus(ADC0_BASE, 0, false));
        //获取采集结果
        ADCSequenceDataGet(ADC0_BASE, 0, ADC0_Value);
                //延时
        //SysCtlDelay(SysCtlClockGet() / 12);
        PWM_CTRL(count,a);
}
}

使用特权

评论回复
15
djz1992|  楼主 | 2015-12-29 13:05 | 只看该作者
dirtwillfly 发表于 2015-12-29 13:00
有可能adc配置不有问题,方便的话建议把代码传上来

有些改动,count就是差值,我已经改掉了,不管它。
ADCvalue就是保存采样值的数组

使用特权

评论回复
16
djz1992|  楼主 | 2015-12-29 13:12 | 只看该作者
dirtwillfly 发表于 2015-12-29 13:00
有可能adc配置不有问题,方便的话建议把代码传上来

代码在上面

使用特权

评论回复
17
dirtwillfly| | 2015-12-29 13:48 | 只看该作者
本帖最后由 dirtwillfly 于 2015-12-29 13:50 编辑

@xyz549040622 帮看看这段程序,我没看出有明显问题

使用特权

评论回复
18
xyz549040622| | 2015-12-29 16:17 | 只看该作者
现在的问题是你前端采集到的电压就不准,所以后级出现问题就情有可原了。我晚上拿launchpad试试,AD误差真有这么大?我看看

使用特权

评论回复
19
pmp| | 2015-12-29 21:11 | 只看该作者
怎么还有表情,是不是去掉

使用特权

评论回复
20
pmp| | 2015-12-29 21:12 | 只看该作者
adc的读取实用滤波的算法

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:人生苦短,冬日苦长,正是青葱,却无骄阳

115

主题

620

帖子

5

粉丝