学习STM32的ADC转化,在开发板上写程序调试。
四个使命:
1.AD以中止方法(单次)收集一路
2.AD以中止方法接连收集四路
3.AD以DMA方法收集一路,DMA深度为一级
4.AD以DMA方法收集四路,每路DMA深度为28级,并滤波,阐明滤波原理。
总结:
第一个使命:ADC以中止方法收集一路ADC,经过装备ADC_InitStructure结构体中的ADC_ScanConvMode,它规矩模数转化作业在扫描形式(多通道)仍是单次形式(单通道),
ADC_InitStructure.ADC_ScanConvMode=DISABLE,为单通道单次形式。
ADC_ContinuousConvMode,定转化是接连仍是单次,ADC_ContinuousConvMode=DISABLE
为单次,ADC_NbrOfChangnel规矩ADC规矩转化的通道数。ADC_NbrOfChannel=1;//敞开1个通道数。
ADC_RegularChannelConfig(ADC1,ADC_Channel_13, 1,ADC_SampleTime_55Cycles5);设置指定规矩组的通道的采样次序和转化时刻。这儿认为只需一路通道,选用的是PC3引脚,对应的通道数是13通道,采样次序也便是1,。
ADC_Cmd(ADC1,ENABLE);使能ADC
ADC_ITConfig(ADC1, ADC_IT_EOC,ENABLE);敞开ADC转化完毕中止。
ADC_ResetCalibration(ADC1);//重置校验寄存器
while(ADC_GetResetCalibrationStatus(ADC1));//等候重置校验成功
ADC_StartCalibration(ADC1);//开端ADC校验
while(ADC_GetCalibrationStatus(ADC1));//等候ADC校验好
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件触发开端转化
由于ADC有一个16位的规矩组数据寄存器(ADC_DR),选用一路转化时能够不必经过DMA传输。这儿就没有装备DMA。
void ADC_IRQHandler(void)
{
ADCConvertedValue=ADC_GetConversionValue(ADC1);
ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
}
当一次转化完毕,DAC发生中止,在中止函数里,读取ADC_DR寄存器中的值,必定铲除中止标志位。
收集出来的数据是16进制数,要经过处理,变成10进制数,详细如下:
(value*100/4096)*33,value是从寄存器读出来的十六进制的数据,经过此改换后就变成10进制数,是个整数,咱们经过串口显现的时分要把小树部分也要显现出来则有:((value*100/4096)*33)/1000,整数部分。
((value*100/4096)*33)%1000/100,((value*100/4096)*33)%100/10),小数部分,
串口装备,我是经过STM32上的串口1与PC机通讯的,详细装备如下:
void USART_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate=9600;波特率9600
USART_InitStructure.USART_WordLength=USART_WordLength_8b;//8位数据位
USART_InitStructure.USART_StopBits=USART_StopBits_1;1个中止位
USART_InitStructure.USART_Parity=USART_Parity_No;无奇偶校验
USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_Init(USART1,&USART_InitStructure);初始化串口装备
USART_Cmd(USART1,ENABLE);使能串口
}
int fputc(int ch,FILE *f)
{
USART_SendData(USART1, (u8)ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET)//查看发送是否完结
{
}
return ch;
}此函数,是把printf输出函数定向到USART。
第一个使命大约便是这个进程,在后面的使命有相同之处,就不重复叙说了。
第二个使命:ADC以中止方法接连收集四路。
首要装备4路模仿输入,我装备的是PC0、PC1、PC2、PC3四个IO口,输入方法为模仿输入,速度选用2M,它们对应的ADC通道别离是10、11、12、13通道。
在第一个使命说了,ADC规矩转化多路采样时,ADC的数据寄存器只需一个16位寄存器,所以有必要选用DMA来传输数据,DMA装备如下:
DMA_InitStructure.DMA_PeripheralBaseAddr=DR_ADDRESS; //DMA对应的外设基地址
DMA_InitStructure.DMA_MemoryBaseAddr=(u32)&Buf; //内存存储基地址,界说的一个数组
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC; //DMA转化形式为SRC形式,由外设搬移到内存
DMA_InitStructure.DMA_BufferSize=4; // DMA缓存巨细,4个(设置DMA在传输时缓冲区的长度)
DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable; //接纳一次数据后,设备地址制止后移(设置DMA的外设递加形式)
DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable; //封闭接纳一次数据后,方针内存地址后移(设置DMA的内存递加形式)
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//界说外设数据长度
DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;
//循环形式敞开,Buf写满后,主动回到初始地址开端传输
DMA_InitStructure.DMA_Priority=DMA_Priority_High;//优先级高
DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;
ADC装备:
//ADC装备
ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//独立转化形式
ADC_InitStructure.ADC_ScanConvMode=ENABLE;//敞开扫描形式
ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//敞开接连转化形式
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//ADC外部开关,封闭状况
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//对齐方法,右对齐方法
ADC_InitStructure.ADC_NbrOfChannel=4;//敞开通道数,4个
ADC_Init(ADC1,&ADC_InitStructure);//初始化ADC
ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1,ADC_Channel_11,2,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_12,3,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1,ADC_Channel_13,4,ADC_SampleTime_55Cycles5);;
//ADC通道组,第10、11、12、13个通道,采样次序别离是1,2,3,4转化时刻55.5个周期
ADC_DMACmd(ADC1, ENABLE);//使能ADC1模块DMA
ADC_Cmd(ADC1, ENABLE);//翻开ADC1
ADC_ResetCalibration(ADC1);//重置ADC1校准寄存器
while(ADC_GetResetCalibrationStatus(ADC1));//等候ADC1校准重置完结
ADC_StartCalibration(ADC1);//开端ADC1校准
while(ADC_GetCalibrationStatus(ADC1));//等候ADC1校准完结
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//使能ADC1软件开端转化
中止是选用DMA中止,当DMA第一轮传输完毕时,设一个标志位,当标志位为1时,标明第一轮转化和传输完结,此刻就能够读取数组中的数据,经过处理就能够经过串口显现出来。
void DMAChannel1_IRQHandler(void)
{
ADC_DMA_OK=1;
DMA_ClearITPendingBit(DMA1_IT_TC1);
}中止函数。
第二个使命大约就这样子。
第三个使命:AD以DMA方法收集一路,DMA深度为一级。
这个使命不难,要害要了解到DMA深度,用自己的言语来了解哈DMA深度吧,当ADC以一路收集时,ADC转化完结就主动把转化成果经过DMA传给意图地址,假如传输一次完毕DMA就发生中止的话,DMA的深度就为一级,假如接连传输N次,DMA的深度就位N级,当然这个N是又规模的,由于受意图地址的内存巨细操控和数据宽度,这个我们应该豆了解的。
这个使命在第一个使命的基础上我经过DMA传输,意思是AD装备没什么差异。DMA装备和第二个使命的差异便是DMA_BufferSize的宽度不同。
#defineDR_ADDRESS(u32)0x4001244cADC的地址
#defineDMA_Count1DMA深度,也便是接连传输的次数
#defineADC_Channle1ADC通道
数据处理和串口通讯这儿不重复叙说。DMA中止和使命二的相似。
第四个使命:AD以DMA方法收集四路,每路DMA深度为128级,并滤波,阐明滤波原理。
这个使命和是个综合性使命,只需弄懂前面三个使命,难点是再怎样滤波,开端的时分我也不知道怎样滤波,搭档提示我才知道怎样滤波的,我大约说哈我的了解,把四路通道收集的数据别离放到四个数组中,然后给他来个排序,降序,升序都行,把首位两个数丢掉,然后加起来求平均值。可是我这儿由于DMA的深度为128级,也便是四个通道别离采样了128次,我们都知道,数据越多,求平均值就越精确,所以我就没有选用什么排序法了,直接给他们别离求平均值,详细如下:
#defineDR_ADDRESS(u32)0x4001244cADC的地址
#defineDMA_Count128DMA深度,也便是接连传输的次数
#defineADC_Channle4ADC通道
for(i=0;i<(ADC_Channle*DMA_Count);i+=4)
{
Value1[j]=Buf[i+0];
Sum1+=Value1[j];
Value2[j]=Buf[i+1];
Sum2+=Value2[j];
Value3[j]=Buf[i+2];
Sum3+=Value3[j];
Value4[j]=Buf[i+3];
Sum4+=Value4[j];
j++;
}
Valu1=Sum1/DMA_Count;
Valu2=Sum2/DMA_Count;
Valu3=Sum3/DMA_Count;
Valu4=Sum4/DMA_Count;
Delay(100000);
printf(“\r\n当时AD_0值:0x%x,电压值:%d.%d%dV\n\r”,
Valu1,((Valu1*100/4096)*33)/1000,((Valu1*100/4096)*33)%1000/100,((Valu1*100/4096)*33)%100/10);
Delay(100000);
printf(“\r\n当时AD_1值:0x%x,电压值:%d.%d%dV\n\r”,
Valu2,((Valu2*100/4096)*33)/1000,((Valu2*100/4096)*33)%1000/100,((Valu2*100/4096)*33)%100/10);
Delay(100000);
printf(“\r\n当时AD_2值:0x%x,电压值:%d.%d%dV\n\r”,
Valu3,((Valu3*100/4096)*33)/1000,((Valu3*100/4096)*33)%1000/100,((Valu3*100/4096)*33)%100/10);
Delay(100000);
printf(“\r\n当时AD_3值:0x%x,电压值:%d.%d%dV\n\r”,
Valu4,((Valu4*100/4096)*33)/1000,((Valu4*100/4096)*33)%1000/100,((Valu4*100/4096)*33)%100/10);
Delay(100000);
关于ADC装备和DMA装备这儿不重复叙说了。