STM32的ADC和串口
扫描二维码
随时随地手机看文章
如果简单的使用USART的话配置相当简单,只要配置一下波特率,数据长度,停止位长度,校验位。然后再设置一下串口的引脚,输入为上后输入,输出为利用推挽输出。这样一来串口就配置好了,如果使用库则一目了然,如果使用寄存器操作会繁琐一点找各个寄存器,因为设置波特率和设置数据长度等这些并不在一个寄存器中设置完成,还有可能忘记个别设置而无法找其原因。但寄存器操作的效率会很高。如下配置:
void USART_Initial(uint32_t Baud)
{
USART_InitTypeDef USART_InitStruct;
USART_GPIO(); //配置串口引脚
USART_InitStruct.USART_BaudRate=Baud; //波特率
USART_InitStruct.USART_WordLength=USART_WordLength_8b;//数据长度
USART_InitStruct.USART_StopBits=USART_StopBits_1;//停止位
USART_InitStruct.USART_Parity=USART_Parity_No;//奇偶校验
USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流失能
USART_InitStruct.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;//使能接收和发送
USART_Init(USART1,&USART_InitStruct);
USART_Cmd(USART1,ENABLE);//打开串口
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开中断,本代码只在接收时用到
}
void USART_GPIO(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_SetBits(GPIOA,GPIO_Pin_9|GPIO_Pin_10);
}
我使能的USART1为PA9和PA10两个串口线。
如果使能到串口中断则在NVIC中设置好中断向量断并设置好优先级,并在串口寄存器中使能该中断。
void NVIC_USART_Initial(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
(中断优先级分组为2)
此时你可以在串口的中断服务代码中写入你想处理的代码。至于你想是接收中断还是发送中断或者传送错误中断还是奇偶校验,侦错误等中断你可以设置USART_ITConfig中设置,在void USART_Initial(uint32_t Baud)函数中最后一句第二个参数进行设置。
如果你想使能printf或者scanf来串口传输请看我的另一篇博文。http://blog.sina.com.cn/s/blog_79fbaced01011tpj.html
而串口的其它功能则没有用到,至于智能卡个人觉得应该挺有意思的,以后兴许会搞搞。而串口的同步模式不知道他和SPI比是不是速度更快,它的传输则由发送数据时产生CLK时钟和些时钟进行同步,接收数据也只有在此时才可以接收,也就是不可以独立的接收数据。
博主也试了串口DMA不中断是可以传输的,但是当我打开DMA传输完成中断时,发现串口没有数据,以为串口速度根不上DMA就提高了波特率发现还是不行。但当我使能DMA半传输中断时能够中断也能传输但是中断程序无法执行。。等高手回答。
下面则是ADC。因为实验仪上的ADC引脚引出来有限,所以很多功能未实现,首先就是ADCON这个东西一直有点混。一直以为使能此位这前校验ADC(手册上说校验ADC是ADCON=0必须在两个周期以上,但手册上又说ADCON=0时ADC消耗基本为0)后试过只有打开此位才可以校验。但是ADCON再次设置时可以启动ADC转换,手册上好像讲是启动规则转换,因为没有度过注入转换所以规则转换可以设置些位,也可以设置ADCx_CR2寄存器器中的外部触发来启动,规则通道则是先设置EXTSEL[2:0]位,如果设置成111即软件触发,后设置位20EXTTRIG位允许外部事件触发,最后设置位22SWSART来启动规则软件触发,而注入触发则同样设置CR2寄存器中的某些对应位来启动。
ADC有很多模式,而双ADC模式个人认为比较经典,或许见识有点少了。哈哈。这里不多说,为什么?没有经验,实验仪提供的资源多,但是随心的少。
SCAN模式,即扫描整个通道。如果规则通道组中有3个通道,则启动通道时转换完第一个自动转换第二个再然后第三个后停止并产生一个EOC事件,如果使能了中断则产生中断。(以前对中断头疼,现在觉得就是个纸老虎)
CONT即单词continue(本来看成count)当设置了SCAN又设置了CONT时将循环的转换通道,即上面转换完三后继续生第一个转换。同样的地方产生EOC。(应该是的,没有实践不敢断定)。
注入模式:一种是外部触发,优先于规则,如果有外部触发将打断正在转换的规则通道。直至完成。
自动注入模式:即转换完成规则通道后自动的切换到注入通道执行转换。
当然ADC还有很多,比如常常配合ADC的DMA。ADC时钟,外部触发的事件啊,等等细节。
配置ADC,这里不将时钟的打开,以上串口也未讲。
void ADC_Initial(void)
{
ADC_InitTypeDef ADC_InitStruct;
ADC_Cmd(ADC1,ENABLE); //启动ADC
System_Delay_us(100); //延时几个ADC周期
ADC_ResetCalibration(ADC1); //重置ADC校验
while(ADC_GetResetCalibrationStatus(ADC1)); //等待重置完成
ADC_StartCalibration(ADC1); //校验ADC
while(ADC_GetCalibrationStatus(ADC1)); //等待校验完成
ADC_InitStruct.ADC_Mode=ADC_Mode_Independent; //独立模式
ADC_InitStruct.ADC_ScanConvMode=DISABLE; //非扫描模式,当有多个ADC通道须要转换时可以使能此位
ADC_InitStruct.ADC_ContinuousConvMode=ENABLE; //连续转换使能
ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; //外部触发条件,这里为软件触发
ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right; //右对齐模式
ADC_InitStruct.ADC_NbrOfChannel=1; //规则通道的个数,放在SQR寄存器的L[3:0]中
ADC_Init(ADC1,&ADC_InitStruct);
ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_239Cycles5); //开启通道10写入规则通道中,并设置第几个转换,转换周期为239
}
以上函数可以参考库手册。
再执行完ADC_Cmd(ADC1,ENABLE);这条语句就可以读通道10的AD转换值了。12位AD值在0~4096之间。然后将这些值打印到串口看其变化。你会发现变化波动还是较大的。可能极差并不会太大。你可以自己进行滤波。
昨天洗完澡回来后并无睡意,所以写了个滤波,但没什么新意,只是不厌其烦的取平均值。最后可以使AD值变化最大的情况下只有一个值的变化,一般情况下采样值都会是同一个值。但这样就大大(很大)牺牲了采样灵敏度。
不过这样的采样滤波不科学。有兴趣的同学可以上网搜下常见的AD的10大软件滤波程序。比较经典。
以下是一个简单的滤波代码。牺牲了速度。
#define GetValueTimes 30
#define DeleteValue 10
uint16_t ADC_GetValue(void)
{
uint8_t i,j;
uint16_t DigitalValue[GetValueTimes],SwapTreg;
uint32_t CalValue=0;
for(i=0;i
{
DigitalValue[i]=ADC_GetConversionValue(ADC1);
}
for(i=0;i
{
for(j=i+1;j
{
if(DigitalValue[i]>DigitalValue[j])
{
SwapTreg=DigitalValue[i];
DigitalValue[i]=DigitalValue[j];
DigitalValue[j]=SwapTreg;
}
}
}
for(i=DeleteValue,j=0;i
{
DigitalValue[j]=DigitalValue[i];
}
for(i=0;i
{
CalValue+=DigitalValue[i];
}
CalValue=CalValue/i;
return (uint16_t)CalValue;
}
#define SampleTimes 10
uint16_t MoveMix(void)
{
uint16_t SampleBuffer[SampleTimes];
uint8_t i,j;
uint32_t CalValue=0;
Lable: for(i=0;i
{
SampleBuffer[i]=ADC_GetValue();
}
for(i=0;i
{
for(j=i;j
{
if(abs(SampleBuffer[i]-SampleBuffer[j])>=20)goto Lable;
}
}
for(i=0;i
{
CalValue+=SampleBuffer[i];
}
CalValue/=i;
return (uint16_t)CalValue;
}
#define SampleTimes2 10
uint16_t MoreMix(void)
{
uint8_t i;
uint32_t CalValue=0;
for(i=0;i
{
CalValue+=MoveMix();
}
CalValue/=i;
return (uint16_t)CalValue;
}
#define SampleOver 5
uint16_t OverMix(void)
{
uint8_t i;
uint16_t OverValue[SampleOver];
Lable2: for(i=0;i
{
OverValue[i]=MoreMix();
}
for(i=0;i
{
if(OverValue[i]!=OverValue[i+1])goto Lable2;
}
return OverValue[0];
}