项目介绍
这个是寒假在家一起练的第二个任务,利用板上的pwm和lpf电路实现信号发生功能,能够生成0-100KHZ的正弦波、三角波、方波,偏置是1.5V,幅度是0-1.5V。
实现的功能
输出正弦波、方波、三角波、频率为0-100khz,每次可改变1khz,幅度为0-1500mv,一次可改变150mv。
设计思路
因为板子上没有ad,所以要用pwm和滤波电路实现输出某一电压的功能,也受到lpf的限制,pwm的频率不能太低,我采用读表法来输出这三种波,用dma循环传输数组给pwm,通过读表的时候,跳着读来实现频率的改变,改变幅度是通过乘以个数。
遇到的困难
困难还是挺多的,因为自己前置课程都没有开始学,所以什么知识都依靠百度,第一个困难就是点灯,点灯点了两天,最后群里大佬发现是编译器版本的问题,然后就是功能的实现,一开始是通过定时器改变pwm的占空比来实现正弦波的输出,但这样只能实现频率很小的正弦波,然后又开始了解dds的知识,但用pwm模拟dds的文章还是很少,自己半懂不懂的瞎搞,主要思路是读表(在代码中实时生成应该也可以,这样幅度的改变会精准些,但我不知道spwm的公式,就直接用spwm软件生成的表),如果这些点挨着读就是生成1khz,隔一个读就是生成2khz,,,但这样还是有问题,当频率很小的时候,读的点会较多,频率还可以,但是频率大点的时候,没法整除,而且差距还小(比如1000除以95得10,1000除以96也得10),这是一开始的思路,即改变dma传输数组的大小,这个数组只包含一个波形而已,后来又好好想了想,发现可以不改变dma传输数组的大小,点不够了,可以循环读表,直到把dma数组填满(如果再加上定时器改变pwm占空比那一部分,是可以实现1khz之下的输出的)。
改变幅度乘以一个数,小数转成整数,它的精度会不怎么好,所以就想到了要不就每次改变都重新生成,但是spwm的公式不明白,再加上flash挺大的,就直接用spwm软件生成了10个表,对应10个挡的幅度,至于三角波是自己手打的,就直接乘数了,不准就不准吧。
编码器采用的下降沿捕获,捕获a的变化,再判断b的电平,网上找的思路,但正反转经常性判断错,所以干脆就不管正转反转了,是的没错,它只有由大变小,再变为最大这一条路可走。
屏幕的使用是我遇到困难最多的,因为其他模块网上资源教学还是蛮多的,这方面我没有找到很多,光点亮它就花费了一天时间,直播看了好多遍,幸好这个项目用到的不多。
硬件介绍与流程图
硬件就用到了lpf、几个按键和屏幕,lpf是二阶低通再加个跟随器,自己算一下截止频率。
代码
输入捕获部分
HAL_TIM_Base_Start_IT(&htim2);
b_last=HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15);
while(flag_tim2<=20){
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15)!=b_last){
HAL_TIM_Base_Stop_IT(&htim2);
flag_tim2=0;
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15)==1){
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_14);
HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_3);
switch(pat){
case 0:
fv=fv+1;
if(fv==10)fv=0;
break;
case 1:
fre=fre+1;
if(fre==101)fre=1;
break;
case 2:
mode=mode+1;
if(mode==3)mode=0;
break;
}
OLED_Clear();
switch(mode){
case 0:
OLED_ShowString(10, 0, "Square ", 8, 1);
break;
case 1:
OLED_ShowString(10, 0, "sine ", 8, 1);
break;
case 2:
OLED_ShowString(10, 0, "Triangular", 8, 1);
break;
}
sprintf((char*)Vpp,"%d ",1500-fv*150);
OLED_ShowString(42, 10, Vpp, 8, 1);
sprintf((char*)FV,"%d ",fre);
OLED_ShowString(30, 20, FV, 8, 1);
OLED_Menu();
OLED_Refresh();
buff_try();
HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_3, (uint32_t*)buff_value, j);
break;
}
else if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15)==0){
break;
}
break;
}
}
HAL_TIM_Base_Stop_IT(&htim2);
flag_tim2=0;
效果展示
心得体会
这一次的寒假一起练项目对我个人来说是一个不小的挑战,因为我可以说只学过微积分,这些知识都是开学后才会学的,真的是从0开始。一开始我无从下手,听过几节直播课后,开始着手查找资料,选择性学习,系统学习肯定来不及。很感谢群里大佬们的答疑解惑还有硬禾提供的帮助,拼拼凑凑的完成了这个设计。经过这次锻炼,我不但了解了stm32的一些知识,还没有在寒假期间肥肥瘫,每一天我都有学一些新知识,这是习惯的养成,希望下一次硬禾的项目中,还会有我的身影。