一:思想
使用stm32产生波形当然肯定要用到DAC了,这是必不可少的,虽然stm32自带三角波生成器,但这里我们主要用dma,这样不论想生成什么波形都可以,只要构造出相应函数列表;
二:函数列表实现
主要就是采样法,在一个波形图上选取多个点,然后把相应数值存起来,等待调用(DMA循环调用),然后通过DAC把数值转换,最后近似得到波形,这种方法其实也就是数学中的描点法;
正弦波:
u16 D_sin[256];
void SineWave_Data()
{
u16 i;
for( i=0;i<=255;i++)
{
D_sin
=(u16)(4095*(sin(i*2*3.1415926/255)+1)/2);
}
}
方波:
u16 D_fang[N];
void Fang_Data()
{
u16 i;
for(i=0;i
{
D_fang= (u16)(0);
}
for( i=N/2;i
{
D_fang=(u16)(4095);
}
}
三角波:
u16 D_saw[N];
void Saw_Data()
{
u16 i;
for( i=0;i
{
D_saw= (u16)(4095*2*i/N);
}
for( i=N/2;i
{
D_saw= (u16)(2*4095*(N-i)/N);
}
}
把生成的数存到相应的数组里就行,等待DMA调用;
三:按键控制频率增减:
//按键初始化
void KEY_init()
{
RCC->APB2ENR|=1<<2; //使能PORTA时钟
RCC->APB2ENR|=1<<4; //使能PORTC时钟
//JTAG_Set(SWD_ENABLE); //关闭JTAG,开启SWD
GPIOA->CRL&=0XFFFFFFF0; //PA0设置成输入
GPIOA->CRL|=0X00000008;
GPIOA->CRH&=0X0FFFFFFF; //PA15设置成输入
GPIOA->CRH|=0X80000000;
GPIOA->ODR|=1<<15; //PA15上拉,PA0默认下拉
GPIOC->CRL&=0XFF0FFFFF; //PC5设置成输入
GPIOC->CRL|=0X00800000;
GPIOC->ODR|=1<<5; //PC5上拉
}
//主函数按键控制部分
//方波和正弦波按键控制
if(KEY_0 == 0 && mode==0 )
{
delay_ms(10);
fang_Hz +=1;
saw_Hz +=1;
mode=1;
}
else if(KEY_1==0 && mode==0)
{
delay_ms(10);
fang_Hz -=1;
saw_Hz -=1;
mode=1;
}
if(KEY_0 == 1 && KEY_1==1)
mode=0;
Init_config(fang_Hz,saw_Hz);//将按键控制加入
四:DAC,DMA,TIME初始化;
//这里只列举正弦波
//DAC初始化
void Dac1_Init()//用于正弦波产生
{
RCC->APB1ENR|=1<<29; //使能 DAC 时钟
RCC->APB2ENR|=1<<2; //使能 PORTA 时钟
GPIOA->CRL&=0XFFF0FFFF;
GPIOA->CRL|=0X00000000; //PA4 模拟输入
DAC->CR|=1<<0; //使能 DAC1
DAC->CR|=1<<2; //使用触发功能 TEN1=1
DAC->CR|=0<<1; //DAC1 输出缓存不使能 BOFF1=1
DAC->CR|=4<<3; //DAC TIM2 TRGO,不过要 TEN1=1 才行
DAC->CR|=0<<6; //不使用波形发生
DAC->CR|=0<<8;//幅值设置
DAC->CR|=1<<12;//DAC1 DMA 使能
DAC->DHR12R1=0;
}
//DMA初始化
void DMA2_init1()
{
RCC->AHBENR|=1<<1; //开启 DMA2 时钟
delay_ms(5); //等待 DMA 时钟稳定
DMA2_Channel3->CPAR=(u32)&(DAC->DHR12R1); //DMA2 外设地址
DMA2_Channel3->CMAR=(u32)D_sin; //DMA2,存储器地址
DMA2_Channel3->CNDTR=256; //DMA2,传输数据量
DMA2_Channel3->CCR=0X00000000; //复位
DMA2_Channel3->CCR|=1<<4; //从存储器读
DMA2_Channel3->CCR|=0<<6; //外设地址非增量模式
DMA2_Channel3->CCR|=1<<7; //存储器增量模式
DMA2_Channel3->CCR|=1<<8; //外设数据宽度为16位
DMA2_Channel3->CCR|=1<<10; //存储器数据宽度16位
DMA2_Channel3->CCR|=1<<12; //最高优先级
DMA2_Channel3->CCR|=1<<13; //最高优先级
DMA2_Channel3->CCR|=0<<14; //非存储器到存储器模式
DMA2_Channel3->CCR|=1<<5; //循环发送模式
DMA2_Channel3->CCR|=1<<0; //开启DMA传输
}
//定时器初始化
void TIM2_Int_Init(u16 arr)//初始化TIM2--正弦
{
RCC->APB1ENR|=1<<0; //TIM2 时钟使能
TIM2->CR1|=0<<4;//向上计数模式
TIM2->ARR=arr; //设定计数器自动重装值
TIM2->PSC=0; //预分频器 7200,得到 10Khz 的计数时钟 频率=72000/(899+1)=80Khz
TIM2->CR2|=2<<4; //选择更新事件作为触发中断(TRGO)
TIM2->CR1|=0x01; //使能定时器2
}
五:总结
以上就可以生成正弦波了,但是还缺少一点点东西把他们组织起来,大家自行添加就行;由于本人才学疏浅,不能将思路很好的梳理,只能提供代码供大家参考;
一:思想
使用stm32产生波形当然肯定要用到DAC了,这是必不可少的,虽然stm32自带三角波生成器,但这里我们主要用dma,这样不论想生成什么波形都可以,只要构造出相应函数列表;
二:函数列表实现
主要就是采样法,在一个波形图上选取多个点,然后把相应数值存起来,等待调用(DMA循环调用),然后通过DAC把数值转换,最后近似得到波形,这种方法其实也就是数学中的描点法;
正弦波:
u16 D_sin[256];
void SineWave_Data()
{
u16 i;
for( i=0;i<=255;i++)
{
D_sin=(u16)(4095*(sin(i*2*3.1415926/255)+1)/2);
}
}
方波:
u16 D_fang[N];
void Fang_Data()
{
u16 i;
for(i=0;i
{
D_fang= (u16)(0);
}
for( i=N/2;i
{
D_fang=(u16)(4095);
}
}
三角波:
u16 D_saw[N];
void Saw_Data()
{
u16 i;
for( i=0;i
{
D_saw= (u16)(4095*2*i/N);
}
for( i=N/2;i
{
D_saw= (u16)(2*4095*(N-i)/N);
}
}
把生成的数存到相应的数组里就行,等待DMA调用;
三:按键控制频率增减:
//按键初始化
void KEY_init()
{
RCC->APB2ENR|=1<<2; //使能PORTA时钟
RCC->APB2ENR|=1<<4; //使能PORTC时钟
//JTAG_Set(SWD_ENABLE); //关闭JTAG,开启SWD
GPIOA->CRL&=0XFFFFFFF0; //PA0设置成输入
GPIOA->CRL|=0X00000008;
GPIOA->CRH&=0X0FFFFFFF; //PA15设置成输入
GPIOA->CRH|=0X80000000;
GPIOA->ODR|=1<<15; //PA15上拉,PA0默认下拉
GPIOC->CRL&=0XFF0FFFFF; //PC5设置成输入
GPIOC->CRL|=0X00800000;
GPIOC->ODR|=1<<5; //PC5上拉
}
//主函数按键控制部分
//方波和正弦波按键控制
if(KEY_0 == 0 && mode==0 )
{
delay_ms(10);
fang_Hz +=1;
saw_Hz +=1;
mode=1;
}
else if(KEY_1==0 && mode==0)
{
delay_ms(10);
fang_Hz -=1;
saw_Hz -=1;
mode=1;
}
if(KEY_0 == 1 && KEY_1==1)
mode=0;
Init_config(fang_Hz,saw_Hz);//将按键控制加入
四:DAC,DMA,TIME初始化;
//这里只列举正弦波
//DAC初始化
void Dac1_Init()//用于正弦波产生
{
RCC->APB1ENR|=1<<29; //使能 DAC 时钟
RCC->APB2ENR|=1<<2; //使能 PORTA 时钟
GPIOA->CRL&=0XFFF0FFFF;
GPIOA->CRL|=0X00000000; //PA4 模拟输入
DAC->CR|=1<<0; //使能 DAC1
DAC->CR|=1<<2; //使用触发功能 TEN1=1
DAC->CR|=0<<1; //DAC1 输出缓存不使能 BOFF1=1
DAC->CR|=4<<3; //DAC TIM2 TRGO,不过要 TEN1=1 才行
DAC->CR|=0<<6; //不使用波形发生
DAC->CR|=0<<8;//幅值设置
DAC->CR|=1<<12;//DAC1 DMA 使能
DAC->DHR12R1=0;
}
//DMA初始化
void DMA2_init1()
{
RCC->AHBENR|=1<<1; //开启 DMA2 时钟
delay_ms(5); //等待 DMA 时钟稳定
DMA2_Channel3->CPAR=(u32)&(DAC->DHR12R1); //DMA2 外设地址
DMA2_Channel3->CMAR=(u32)D_sin; //DMA2,存储器地址
DMA2_Channel3->CNDTR=256; //DMA2,传输数据量
DMA2_Channel3->CCR=0X00000000; //复位
DMA2_Channel3->CCR|=1<<4; //从存储器读
DMA2_Channel3->CCR|=0<<6; //外设地址非增量模式
DMA2_Channel3->CCR|=1<<7; //存储器增量模式
DMA2_Channel3->CCR|=1<<8; //外设数据宽度为16位
DMA2_Channel3->CCR|=1<<10; //存储器数据宽度16位
DMA2_Channel3->CCR|=1<<12; //最高优先级
DMA2_Channel3->CCR|=1<<13; //最高优先级
DMA2_Channel3->CCR|=0<<14; //非存储器到存储器模式
DMA2_Channel3->CCR|=1<<5; //循环发送模式
DMA2_Channel3->CCR|=1<<0; //开启DMA传输
}
//定时器初始化
void TIM2_Int_Init(u16 arr)//初始化TIM2--正弦
{
RCC->APB1ENR|=1<<0; //TIM2 时钟使能
TIM2->CR1|=0<<4;//向上计数模式
TIM2->ARR=arr; //设定计数器自动重装值
TIM2->PSC=0; //预分频器 7200,得到 10Khz 的计数时钟 频率=72000/(899+1)=80Khz
TIM2->CR2|=2<<4; //选择更新事件作为触发中断(TRGO)
TIM2->CR1|=0x01; //使能定时器2
}
五:总结
以上就可以生成正弦波了,但是还缺少一点点东西把他们组织起来,大家自行添加就行;由于本人才学疏浅,不能将思路很好的梳理,只能提供代码供大家参考;
举报