【菜鳥入門】stm32 之 ADC 模數轉換
今天對ADC進行了研究,個人感覺,ADC的配置相對也對比較複雜一點,因為需要配置的暫存器是比較多的!
在datasheet 關於ADC的簡介中,明確說明ADC的輸入時鐘不得超過14M,他是有PCLK2經過分頻得來的
這次我們選用ADC1_IN0作為講解的物件,ADC1_IN0 -->PA0
所以在配置時鐘的時候要配置PA0和ADC1,關於怎麼配置,已經說的很清楚了。
在配置PA0的輸入模式方面我要說明一下,有好多人在這個地方還是很鬱悶的
在8.1.11 外設GPIO的配置中每種配置都說的很清楚,如果我們對那中模式配置有疑問,我們都可以直接在這裡查詢
這裡的ADC我們採用模擬輸入模式:
所以我們這裡需要把PA1配置為0000b
輸入配置完成,在開頭我已經強調過了,ADC的時鐘不能超過14MHz,所以我們要對ADC的時鐘進行些操作
RCC_CFGR這個暫存器找了我半天,我就感覺在RCC裡面配置,但是一直找不到ADC的配置項,後來在網上找了半天,才知道ADC的頻率配置在這裡選擇
我一般在配置系統時鐘的時候喜歡配置為72MHz,即PCLK2 = 72MHz
所以為了滿足我們的ADC,我們至少需要6分頻,當然8分頻也可以,好吧廢話了一句。。
我們這裡就6分頻吧:RCC->CFGR &= ~(3<<14);RCC->CRGR |= 2<<14;
這裡得到的ADC時鐘為12MHz,時鐘配置完成後,那我們就來專心配置ADC register了
當然,有經驗的人,不用想,直接先找到控制暫存器(CR ,Control Register)
ADC的控制暫存器比較多,我剛開始看的比較鬱悶,然後再李想老師的程式碼裡面找了一段(因為最近比較忙,沒有時間,所以喜歡搞定現成的程式碼研究下);當然大家也可以只要,只要你把別人的配置方法,配置原理學會了,也是很不錯的,有時候我道覺得這是一種比較學習的快捷辦法!這裡給大家交流下學習經驗
先看看ADCx_CR1
CR1暫存器大部分位是管理WATCH DOG的,我們一般不怎麼用WATCH DOG,在430上我基本上沒有用過看門狗,感覺這個狗不是很聽話,我也不是很瞭解他,所以以後用到了再說吧。
首先是雙模式選擇
我們需要注意下:在ADC2和ADC3中這些位為保留的,所以以後我們再配置的時候注意下,還有下面的幾行
這裡我們用獨立模式0000b,在此模式中,雙ADC同步不工作,每個ADC介面獨立工作;
關於模式大家可以看看11.9章
至今我還沒有明白這個掃描模式時幹嘛用的!誰會了,幫忙指點下,謝謝了。
關於CR2的配置相對比較多的!
我們這裡不使用外部事件來啟動轉換,直接用軟體來轉換,所以20位我們要置0,從而在選擇啟動規則通道組轉換的外部事件我們就只能用SWSTART(Software Start)
我們用的是ADC1,而且還關閉了外部啟動轉換,所以我們這裡就選擇111
為了保證資料資料的實時性,我們需要進行連續轉換,我不知道李想老師為什麼選用單次轉換,不過也無所謂了。
然後為了保證讀書的方便,我們可以把資料儲存的時候進行右對齊;這樣我們就不需要進行移位的操作了,直接讀就ok 了。
關於SQR暫存器,規則序列暫存器,聽著都糾結,我們只用一個通道,所以我們就二話不說的配置為0000b
通道的取樣時間,我的觀念是取樣時間越長越精確,經過測試確實是這樣
由於我們用的是CH1,所以我們呢就要配置SMPR的SMP1設定為111
這些配置完了,那我們就來啟動ADC吧。
還是CR2,開啟ADC,進行矯正復位,矯正。
完成後,就沒有了,只剩下讀資料了。
讀資料我要說下:
我們要先配置我們要取樣的通道,然後開啟控制暫存器CR2上的開始轉換 Start Conversion
注意檢測狀態暫存器裡面的轉換狀態,轉換結束,他會把EOC位置1
然後我們就可以讀資料了;
現在附上程式碼,大家可以參考程式碼看看:
/* adc.c */
#include <stm32f10x.h>
void adc1_init()
{
RCC->APB2ENR |= 1<<2;
GPIOA->CRL &= ~(0xf<<0);
GPIOA->CRL |= 0x0<<0;
RCC->APB2ENR |= 1<<9;
RCC->APB2RSTR |= 1<<9;
RCC->APB2RSTR &= ~(1<<9);
RCC->CFGR &= ~(3<<14);
RCC->CFGR |= 2<<14; // 6 div PCLK2 / 6 = 12MHz
ADC1->CR1 &= ~(0xf<<16);
ADC1->CR1 |= 0<<16; //Set Indenpendence Mode
ADC1->CR1 &= ~(1<<8); //Scan Mode Disable
/* Config Control Register 2*/
ADC2->CR2 |= 1<<1; //Continuous conversion mode
ADC1->CR2 &= ~(7<<17); //Clear
ADC1->CR2 |= 7<<17; //software start
ADC1->CR2 |= 1<<20; //Conversion on external event enable
ADC1->CR2 &= ~(1<<11); //Right Alignment
ADC1->SQR1 &= ~(0xf<<20);
ADC1->SQR1 |= 0<<20;
ADC1->SMPR2 &= ~(0x7<<3);
ADC1->SMPR2 |= 7<<3;
ADC1->CR2 |= 1<<0; //Start ADC to Calibration
ADC1->CR2 |= 1<<3;
while(ADC1->CR2 & 1<<3);
ADC1->CR2 |= 1<<2;
while(ADC1->CR2 & 1<<2);
}
unsigned short get_adc(unsigned char ch)
{
ADC1->SQR3 &= ~(0xf<<0);
ADC1->SQR3 |= ch;
ADC1->CR2 |= 1<<22;
while(!(ADC1->SR & 1<<1));
return ADC1->DR;
}
主函式::::/* main.c */
#include <stm32f10x.h>
#include "stdio.h"
#include "init.h"
#include "usart.h"
#include "adc.h"
int main()
{
char buff[256];
sys_init(9);
rs232_init(CPU_72M,9600);
rs232_send_byte('\n');
adc1_init();
while(1)
{
sprintf(buff,"V:%.3f V\n",3.3*get_adc(1)/4096);
rs232_send_str(buff,strlen(buff));
delay_ms(1000);
}
}
ADC有的地方我還沒有搞的完全懂,願意聽各位大神指點!