单片机输出模拟量,主要有两种方式,通过DA模块或者PWM模块输出;
以我目前经常使用的ST的Cortex-M0系列的处理STM32F051处理器为例。
在我负责的产品中,有一款产品需要由单片机产生铃声,为了节省成本,没有使用专用的铃声芯片,而是由单片机的D/A模块输出模拟量以产生铃声,同时根据外接的可调电组,调节输出的电压幅度以调节的音量。
具体实现原理如下:
1)将产品部提供的wmv的铃声文件,通过goldenwave软件按照16kHz的采样率重新采样。
2)将重采样得到的音频数据进行放缩平移转成偏置为128,范围为0-255之间的8bit整型的数据。
3)将得到的数据存储到外置的SPI Flash。
4)选用单片机的某个定时器,将定时器的定时时间设置为62.5us,并使用中断。
5)配置单片机的DA以及SPI模块,在定时器中断时,通过SPI模块读取其FIFO的数值,将读到的数值通过DA模块输出到端口,同时发送命令通过SPI模块读取下一个byte的数据。
定时器中断代码如下:
if(SPI1->SR & SPI_SR_RXNE)\
{
temp = SPI_Receive(SPI1);
DAC->DHR12R1 = (((U16)temp) << 2);
DAC->DHR12R1 = (((U16)temp) << 4);
}
if(SPI1->SR & SPI_SR_TXE)
{
SPI_SendData(SPI1, 0xFF);
addr ++;
}
另外一种常用的模拟量输出的方式为PWM输出。
即通过频率固定,占空比可调的信号输出PWM,PWM带通过低通滤波电路滤成幅度受占空比控制的模拟量信号;
可以通过单片机的PWM模块或者是直接用定时器中断产生PWM信号。
PWM信号通过简单的R、C低通滤波电路就可以滤成模拟量;
一般R、C的时间常数需要选为10倍的PWM信号的周期。
模拟量输出的幅度为PWM信号的输出高电平*占空比;
比如以下的程序,就是通过单片机的PWM模块输出10KHz的占空比,并通过时间常数为1ms(电阻为10k,电容为0.1uF)的R、C过滤成模拟量;
用来接入直流电机控制器,调节直接电机的转速。
void fnMT_InitPWM(void){
SET_IO_AFMODE_PP(P_MOTOR_B_PULSE_PORT, P_MOTOR_B_PULSE_PIN);
fnMN_MAPR_And(~AFIO_MAPR_TIM1_REMAP)
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;//Timer1 clock enable
MOTOR_PWM->CR1 = TIM_CR1_ARPE;//自动加载
MOTOR_PWM->PSC = (64 - 1);//fck_psc/(PSC[15:0] + 1)=1MHz
MOTOR_PWM->EGR = 0x0001;//Reload immediate
MOTOR_PWM->CCMR1 = 0x0068;//使能PWM功能,并开启自动加载CH1
MOTOR_PWM->ARR = (U16)(MOTOR_FREQ_DEFAULT - 1);
MOTOR_PWM->CCR1 = 100;
MOTOR_PWM->BDTR = 0x8000;
MOTOR_PWM->EGR = 0x0001;
MOTOR_PWM->CCER |= 0x0009;
MOTOR_PWM->DIER |= 0x000001;
MOTOR_PWM->CR1 |= 0x0001;
}
void fnMT_ConPWM(U16 period, U16 duty){
MOTOR_PWM->ARR = period;
MOTOR_PWM->CCR1 = duty;
}