2017-08-31 13:48:26 ssss992 阅读数 12922
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4000 人正在学习 去看看 朱有鹏

       通过改变单片机的DA输出电压,可以得到各种各样的电压波形输出,下面介绍产生正弦波形需送DA的数据是如何计算的。

       首先既然是正弦波,那么就要确定要输出一个周期正弦波的采样点数point,即由多少点组成了一周期的正弦波,还要知道单片机输出DA的数字值maxnum是多少,比如

8位DA,maxnum=256。10位DA,maxnum=1024。

       知道以上两个值后,就开始计算需要得到的正弦波DA数据了,我设置一个正弦波由61个点组成,所选DA最大数字输入值为1024,那么我的正弦波数据数组就有61个数据,即sin_tab[61],也就是把一个正弦波360度,分成了61份,那么每份就是360÷61=5.901度,这样就可以计算出61点中每个点对应的角度值jiaodu,有了角度值就可以算出来角度对应的正弦值,利用正弦值和输出DA的数字值maxnum,就可以计算出对应DA输入的数值了。

公式为:

 sin_tab[i]=(maxnum/2)*sin(x)+(maxnum/2); //  i代表某点      x为某角度对应的弧度      弧度=角度*(π/180);  //(maxnum/2)为正弦波零点处对应DA输入值;即DA满量程的一半;

在51单片机运行了以下函数,DA输出波形完美,验证产生的DA数据无误。

 #include<math.h> //注意需添加此头文件,包含了求正弦值函数sin(弧度值);

//获取不同点数的正弦波数据
//point: 一周期内的取样点数
//maxnum: 一周期内对应DA输出最大值
void getSinTab(uchar point,uint maxnum)
{
uchar i=0; 
float x;   //弧度
float jiao;//角度 分度角
jiao=360.000/point; 

  for(i=0;i<point;i++)
{
x=jiao*i;    //得到角度值
   x=x*0.01744; //角度转弧度  弧度=角度*(π/180)
      sin_tab[i]=(maxnum/2)*sin(x)+(maxnum/2);
}

}

// sin_tab[i] 为得到的正弦波数据,用于送给DA输出。


2019-10-24 22:19:06 Mybadguy 阅读数 65
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4000 人正在学习 去看看 朱有鹏

被测正弦波基本要求:频率范围500Hz-5KHz,峰峰值100mV-3V;

  1. 测频率;
  2. 测均值;
  3. 测有效值。

请问这个功能实现的思路是什么???

2019-09-15 12:09:20 gd1984812 阅读数 148
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4000 人正在学习 去看看 朱有鹏

前面的文章介绍了单片机控制步进电机四相四拍、四相八拍的方式。用的是持续电平驱动,这种驱动方式电机的噪音大,震动明显,下面介绍正弦波驱动方式,这种方式能很好的解决噪音和震动问题。

首先需要准备下stm32的正弦波PWM表,可以用EXCEL生成。

配置单片机定时器的PWM输出。

void TIM_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_OCInitTypeDef  TIM_OCInitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
        
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

        GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
        
        TIM_TimeBaseStructure.TIM_Period=512;        
        TIM_TimeBaseStructure.TIM_Prescaler= 7;        
        TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;                
        TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;                
        TIM_TimeBaseStructure.TIM_RepetitionCounter=0;        
        TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
        TIM_OCInitStructure.TIM_Pulse=512;                 
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
        
        TIM_OC1Init(TIM1, &TIM_OCInitStructure);
        TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
        TIM_OC2Init(TIM1, &TIM_OCInitStructure);
        TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
        TIM_OC3Init(TIM1, &TIM_OCInitStructure);
        TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
        TIM_OC4Init(TIM1, &TIM_OCInitStructure);
        TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);
        
        TIM_ARRPreloadConfig(TIM1, ENABLE);        
        TIM_Cmd(TIM1, ENABLE);
        
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  
  NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);                                                                                                 
        
        TIM_CtrlPWMOutputs(TIM1,ENABLE);
        TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);                                                                                
}

配置定时器的数据更新中断,在中断里更新CCR的值改变占空比。

void TIM1_UP_IRQHandler(void)
{        
        if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)        
         {                
                pwm1_index++;if(pwm1_index>36)pwm1_index=0;
                pwm2_index++;if(pwm2_index>36)pwm2_index=0;
                pwm3_index++;if(pwm3_index>36)pwm3_index=0;
                pwm4_index++;if(pwm4_index>36)pwm4_index=0;
                TIM1->CCR1 = indexWave[pwm1_index];        
                TIM1->CCR2 = indexWave[pwm2_index];        
                TIM1->CCR3 = indexWave[pwm3_index];        
                TIM1->CCR4 = indexWave[pwm4_index];        
                TIM_ClearITPendingBit (TIM1, TIM_IT_Update);        
        }
}

至此可以看到定时器输出的符合正弦波规律的PWM波。

可以对比下用正弦波代替持续电平的效果

2019-08-18 13:19:10 weixin_44587775 阅读数 488
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4000 人正在学习 去看看 朱有鹏

以下为适用于各类单片机:
  改变单片机的DAC输出电压,可以得到需要的电压波形输出,下面介绍正弦波所需的DAC数据是如何计算的。
  首先既然是正弦波,那么就要确定输出一个周期正弦波的采样点数point,即由多少点组成了一周期的正弦波,还要知道单片机输出DAC的数字值maxnum是多少,比如8位DAC,maxnum=256。10位DAC,maxnum=1024。
  知道以上两个值后,就开始计算需要得到的正弦波DA数据了,我设置一个正弦波由61个点组成,所选DA最大数字输入值为1024,那么我的正弦波数据数组就有61个数据,即sin_tab[61],也就是把一个正弦波360度,分成了61份,那么每份就是360÷61=5.901度,这样就可以计算出61点中每个点对应的角度值angle,有了角度值就可以算出来角度对应的正弦值,利用正弦值和输出DA的数字值maxnum,就可以计算出对应DA输入的数值了。

公式为:

 sin_tab[i]=(maxnum/2) * sin(x)+(maxnum/2); //  i代表某点      x为某角度对应的弧度  
 弧度=角度*(π/180;  //(maxnum/2)为正弦波零点处对应DA输入值;即DA满量程的一半;

下面为代码:

#include<math.h> //注意需添加此头文件,包含了求正弦值函数sin(弧度值);
//获取不同点数的正弦波数据
//point: 一周期内的取样点数
//maxnum: 一周期内对应DA输出最大值
void getSinTab(uchar point,uint maxnum)
{
uchar i=0; 
float x;   //弧度
float angle;//角度 分度角
angle=360.000/point; 

  for(i=0;i<point;i++)
  {
      x=angle*i;    //得到角度值
      x=x*0.01744; //角度转弧度  弧度=角度*(π/180)
      sin_tab[i]=(maxnum/2)*sin(x)+(maxnum/2);
  }
}

// sin_tab[i] 为得到的正弦波数据,用于送给DA输出。

2019-10-12 17:39:02 weixin_39403423 阅读数 108
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4000 人正在学习 去看看 朱有鹏

@STM32f103产生50Hz—20kHz正弦波

频率幅值可调正弦波

很多时候我们需要生成一些特定频率和幅值的正弦波波形,近期个人研究这部分的原理和代码,将成果做一下分享,如有不对之处,欢迎大佬补刀

试验工具

  1. stm32f103zet6的开发板;
  2. 使用DMA、DAC、TIM定时器生成正弦波;
  3. 普源示波器一台;
  4. 万用表一台;

##原理

通过定时器每隔一段时间触发一次DAC转换,然后通过DMA发送正玄波码表值给DAC.
当需要改变频率HZ时,只需要修改定时器频率即可(最高只能达到20KHz)
当需要改变正玄波的正峰峰值/负峰峰值时,只需要修改正玄波码表即可

##部分代码实现

粘出部分代码,详情请见网盘链接,有完整代码分享

部分代码

#define HZ(x) (u16)(72000000/sizeof(Sine12bit)*2/x)   //计算Hz

#define DAC_DHR12R1 0x40007408 //外设DAC通道1的基地址


>u16 Sine12bit[256] = {  //正弦波描点
 2048, 2098, 2148, 2198, 2248, 2298, 2348, 2398, 2447, 2496,
 2545, 2594, 2642, 2690, 2737, 2785, 2831, 2877, 2923, 2968,
 3013, 3057, 3100, 3143, 3185, 3227, 3267, 3307, 3347, 3385,
 3423, 3460, 3496, 3531, 3565, 3598, 3631, 3662, 3692, 3722,
 3750, 3778, 3804, 3829, 3854, 3877, 3899, 3920, 3940, 3958,
 3976, 3992, 4007, 4021, 4034, 4046, 4056, 4065, 4073, 4080,
 4086, 4090, 4093, 4095, 4095, 4095, 4093, 4090, 4086, 4080,
 4073, 4065, 4056, 4046, 4034, 4021, 4007, 3992, 3976, 3958,
 3940, 3920, 3899, 3877, 3854, 3829, 3804, 3778, 3750, 3722,
 3692, 3662, 3631, 3598, 3565, 3531, 3496, 3460, 3423, 3385,
 3347, 3307, 3267, 3227, 3185, 3143, 3100, 3057, 3013, 2968,
 2923, 2877, 2831, 2785, 2737, 2690, 2642, 2594, 2545, 2496,
 2447, 2398, 2348, 2298, 2248, 2198, 2148, 2098, 2047, 1997,
 1947, 1897, 1847, 1797, 1747, 1697, 1648, 1599, 1550, 1501,
 1453, 1405, 1358, 1310, 1264, 1218, 1172, 1127, 1082, 1038,
 995, 952, 910, 868, 828, 788, 748, 710, 672, 635,
 599, 564, 530, 497, 464, 433, 403, 373, 345, 317,
 291, 266, 241, 218, 196, 175, 155, 137, 119, 103,
 88, 74, 61, 49, 39, 30, 22, 15, 9, 5,
 2, 0, 0, 0, 2, 5, 9, 15, 22, 30,
 39, 49, 61, 74, 88, 103, 119, 137, 155, 175,
 196, 218, 241, 266, 291, 317, 345, 373, 403, 433,
 464, 497, 530, 564, 599, 635, 672, 710, 748, 788,
 828, 868, 910, 952, 995, 1038, 1082, 1127, 1172, 1218,
 1264, 1310, 1358, 1405, 1453, 1501, 1550, 1599, 1648, 1697,
 1747, 1797, 1847, 1897, 1947, 1997 };


> /*************************************************************
Function  :  set_Sine12bit
Description :设置正玄波码表
Input  :   MAX(正峰峰值) MIN(负峰峰值)
return  :  none
*************************************************************/ 
 void Set_Sine12bit(float MAX,float MIN)
{
         int i;
         float  jiaodu=0;

>float MID=(MAX+MIN)/2.0;                         //中间峰值

>if(MAX>3.3) MAX=3.3;

>else if(MAX<=MIN) MIN=0;
for(i=0;i<256;i++)
         {
             jiaodu=i*0.0247369;      //当i =127时,表示为180度,由于sin()是弧度制,所以需要转换
             Sine12bit[i]=  ((float)sin(jiaodu)*(MAX-MID)+MID)*1241.212;    //1241.212是比例,等于4096/3.3                      
         }  
}

>/*************************************************************
Function  :   Set_Period
Description :设置频率hz
Input  :   value(需要设置的频率hz值)
return :  none
*************************************************************/ 

>void  Set_Period(u32 value)
{
     TIM_ARRPreloadConfig(TIM2,DISABLE);
     TIM2->ARR=HZ(value);               //更新预装载值 
     TIM_ARRPreloadConfig(TIM2,ENABLE);
}

代码连接

链接: [link](https://pan.baidu.com/s/1wKqJj4An28inXTDc4Umnxw)

提取码:4qrp
在这里插入图片描述
图片说明:只需通过串口向单片机写入需要配置的内容即可,例如发送50,2,0,即可输出50Hz,最大峰值2V,最小峰值0V的正弦波。默认会输出50HZ,3.3,0的正弦波,可以通过用万用表测量DAC的输出引脚,用DC档,可以测的1.65V的电压。

博文 来自: yu_mi__
没有更多推荐了,返回首页