提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、如何产生正弦波?
  • 二、生成采样数值函数
    • 1.函数生成DAC数组函数
    • 2.通过高级定时器TIM1更新中断控制DAC输出
  • 三、通过四个按钮控制输出的频率和幅度
  • 四、下面是我的实测波形,附上程序百度网盘
  • 总结

前言

这个程序非常简单,说白了就是每隔一段时间改变引脚输出的电压,就能得到一个正弦波。

主要是为了方便大家调试FFT,有一个输入大于0小于3.3V取样信号,方便大家学习。

一、如何产生正弦波?

本文采用查表法的方式生成一个数值范围为[0,4096]的正弦波数组,通过定时器更新中断不断以DAC进行输出,从而产生一个正弦波,并且通过改变定时器的预装载值(ARR)或者预分频系数(psc),改变进入中断的时间进而改变正弦波频率。

二、生成采样数值函数

代码如下:

void out_sine(void){ double index = 250;//250个数据 float pi = 3.141592; int fori = 0; float outv = 0; for(;fori <index;fori++) {outv = 0.5*(sin((2*pi)/index*fori)+1)*4095;printf("%.0f,\t",outv);if(!((fori+1)%8)) printf("\r\n");//将数据打印出来 } }

下表是通过串口软件打印出来的数据,有了这个一维数组我们只需要将数组里的值依次赋给DAC就能得到正弦波啦。

const u16 Sine12bit_250[250] = {2048,2099,2150,2202,2253,2304,2355,2406,2456,2507,2557,2606,2656,2705,2753,2801,2849,2896,2942,2988,3034,3079,3123,3166,3209,3251,3292,3333,3372,3411,3449,3486,3522,3558,3592,3625,3657,3689,3719,3748,3776,3803,3829,3854,3878,3900,3921,3942,3961,3978,3995,4010,4024,4037,4048,4059,4068,4075,4082,4087,4091,4094,4095,4095,4094,4091,4087,4082,4075,4068,4059,4048,4037,4024,4010,3995,3978,3961,3942,3921,3900,3878,3854,3829,3803,3776,3748,3719,3689,3657,3625,3592,3558,3522,3486,3449,3411,3372,3333,3292,3251,3209,3166,3123,3079,3034,2988,2942,2896,2849,2801,2753,2705,2656,2606,2557,2507,2456,2406,2355,2304,2253,2202,2150,2099,2048,1996,1945,1893,1842,1791,1740,1689,1639,1588,1538,1489,1439,1390,1342,1294,1246,1199,1153,1107,1061,1016,972,929,886,844,803,762,723,684,646,609,573,537,503,470,438,406,376,347,319,292,266,241,217,195, 174,153,134,117,100,85,71,58,47,36,27,20,13,8,4,1,0,0,1,4,8,13,20,27,36,47,58,71,85,100,117,134,153,174,195,217,241,266,292,319,347,376,406,438,470,503,537,573,609,646,684,723,762,803,844,886,929,972,1016,1061,1107,1153,1199,1246,1294,1342,1390,1439,1489,1538,1588,1639,1689,1740,1791,1842,1893,1945,1996,};

2.通过高级定时器TIM1更新中断控制DAC输出

代码如下:

#define CLIP_ROT(V,MIN,MAX) ( ( V>MAX?MIN:(V<MIN?MAX:V) ) )void AdcPushData(){static int DAC_index_1 = 0;DAC_SetChannel1Data(DAC_Align_12b_R,(Sine12bit_250[DAC_index_1])*DacAmp/10);//250个点4Khz(0.4ms)DAC_index_1++;DAC_index_1 = CLIP_ROT(DAC_index_1,0,250);}void Timer1_Init(u16 arr,u16 psc){TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrecture;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);/*使能定时器1的时钟*/NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_TIM10_IRQn;/*定时器1的中断通道使能*/NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;/*定时器1的中断通道使能*/NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;/*抢占优先级*/NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;/*响应优先级*/NVIC_Init(&NVIC_InitStructure);/*配置中断分组,并使能中断*/TIM_TimeBaseInitStrecture.TIM_Period = arr;/*重装载寄存器*/TIM_TimeBaseInitStrecture.TIM_Prescaler = psc;/*预分配*/TIM_TimeBaseInitStrecture.TIM_ClockDivision = TIM_CKD_DIV1;/*时钟分频*/TIM_TimeBaseInitStrecture.TIM_CounterMode = TIM_CounterMode_Up;/*向上计数*/TIM_TimeBaseInitStrecture.TIM_RepetitionCounter = 0;/*重复计数寄存器*/TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStrecture);/*初始化*/TIM_ClearFlag(TIM1,TIM_FLAG_Update);/*清更新标志位*/TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE);/*使能中断*/TIM_Cmd(TIM1,ENABLE);/*使能计数*/}void TIM1_UP_TIM10_IRQHandler(void){if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET){//判断TIM中断发生与否:TIM 中断源 TIM_ClearITPendingBit(TIM1, TIM_IT_Update);//清除中断标志位,否则卡死在中断里 /***************在此处添加中断执行内容******************/AdcPushData();LED1 = ~LED1;}}

中断配置好了就可以输出一个好看的正弦波了,那怎么调频和调幅呢?

二、通过四个按钮控制输出的频率和幅度

代码如下:

static int DacAmp = 0.0;void Sine(){u16 key=KEY_Scan(0);static u16 F = 128 - 1 ;//默认50HZswitch(key){case WKUP_PRES:DacAmp +=1;break;//case KEY1_PRES:DacAmp -=1;break;case KEY2_PRES:F += 10;break;//改变TIM1的预装载值,从而改变频率case KEY0_PRES:F -= 10;break;default:break;}DacAmp = CLIP_ROT(DacAmp,0,10);TIM1->ARR = F;// 改变预分配系数也是可行的,(PSC)TIM1->PSC =F;}

按下WKUP_PRES和KEY1_PRES,正弦波幅值变化,KEY2_PRES和KEY0_PRES控制频率变化。

三、下面是我的实测波形

附上代码:链接:https://pan.baidu.com/s/1aXAH2Qu5vF8uVKZdXpQx0g” />总结

额,不知道写啥,有问题请留言,如果觉得有用的话,请点个赞,不胜感激。