STM32 mikrovezérlők programozása ARM Keil környezetben 7. Analóg Digitális átalakító (ADC) 1
Felhasznált és ajánlott irodalom Joseph Yiu: Cortex-M for Beginners Joseph Yiu: Thee Definnitive Guide To Thee ARM CORTEX-M3 Muhammad Ali Mazidi, Shujen Chen, Eshragh Ghaemi: STM32 Arm Programming for Embedded Systems Alexander Tarasov: Курс «Штурмуем STM32» Warren Gay: Beginning STM32 - Developing with FreeRTOS, libopencm3 and GCC ARM Keil MDK Gettiing started STM32F103C8 adatlap és termékinfo STM32F103 Family Reference Manual 2
Az ADC főbb jellemzői Az STM32F103C8 mikrovezérlő 2 db 12-bites ADC-vel rendelkezik Bemenő feszültség tartománya: 0 < V IN < 3.6 V (V SS < V IN < V DDA ) Konverziós idő: 1 μs @ 56 MHz (1.17 μs @ 72 MHz) Szingli és folytonos konverziós módok Pásztázó mód több csatorna automatikus méréséhez Önkalibrálás Csatornánként beállítható sorrend és mintavételezési idő Injektált csatornák közbevetetti mérése Külső triggerelés a reguláris és az injektált csatornák méréséhez Duál módú mérések a két ADC összekapcsolásával DMA adatátviteli kérelem generálása konverzió végén 3
Az ADC blokkvázata max. 14 MHz /2, /4, /6, /8 max. 72 MHz 4
Az ADC funkcionális leírása ADC ki-/bekapcsolás: az ADCx_CR2 regiszter ADON bitjével ADC órajel: APB2 busz PCLK2 órajeléből leosztással (/2, /4, /6, /8), ami az RCC_CFGR regiszter ADC_PRE[1:0] bitjeivel állítható be Csatorna kiválasztás: elvileg 16+2, gyakorlatilag csak 10+2 csatorna áll rendelkezésre, melyek csoportokba rendezhetők: reguláris csatornák: max. 16+2 pásztázandó csatorna, melyek száma és tetszőleges sorrendje az ADCx_SQRn regiszterekben adható meg injektált csatornák: legfeljebb 4 db pásztázandó csatorna, melyek melyek száma és sorrendje az ADCx_JSQR regiszterben adható meg Belső hőmérő: az ADC1_IN16 csatornán érhető el V25 = (1.43 ± 0.09) V, Avg_Slope = (4.3 ± 0.6) mv Belső referencia: (1.20±0.04) V, ADC1_IN17 csatornán érhető el 5
Szingli konverziós mód Ebben a módban az ADC egyetlen konverziót végez A konverzió indítható az ADC_CR2 regiszter ADON bitjével, vagy külső triggerjellel, miközben a CONT bit 0-ra van állítva Ahogy a kiválasztotti csatornában a konverzió véget ér: Ha reguláris csatornában mértünk: Az eredmény a 16-bites ADC_DR regiszterbe kerül Az EOC (End Of Conversion) jelzőbit 1-be áll és megszakítás keletkezik, ha az EOCIE engedélyező bit 1-be van állítva Ha injektált csatonában történt a mérés: Az eredmény a 16-bites ADC_DRJ1 regiszterbe kerül A JEOC (End Of Conversion Injected) jelzőbit 1-be áll és megszakítás keletkezik, ha a JEOCIE engedélyező bit 1-be van állítva Az ADC ezután leáll 6
A reguláris csatornákhoz tartozó regiszterek A reguláris csatornák használatához az ADC-k alábbi regisztereit használjuk Az üzemmódot a CR1, CR2 regiszterekben állíthatjuk be, a csatorná(ka)t az SQRn regiszterek választják ki, a mintavételezési időt az SMPRn regiszterek szabják meg Regiszternév ADC_SR Funkció ADC Status register ADC_CR1 ADC Control Register 1. ADC_CR2 ADC Control Register 2. ADC_SMPR1 ADC sample time register 1. ADC_SMPR2 ADC sample time register 2. ADC_SQR1 ADC regular sequence register 1. ADC_SQR2 ADC regular sequence register 2. ADC_SQR3 ADC regular sequence register 3. ADC_DR ADC regular data register 7
Az ADC fontosabb regiszterei ADC_SR ADC Status Register STRT - Regular channel Start flaag, JSTRT - Injected channel Start flaag JEOC End of conversion (injected), EOC End of conversion (regular) AWD Analog watchdog eseményjelző ADC_CR1 ADC Control Register 1. SCAN többcsatornás pásztázás engedélyezése 8
Az ADC fontosabb regiszterei ADC_CR2 ADC Control register 2. EXTSEL[2:0] triggerforrás választás EXTTRIG triggerelés engedélyezés SWSTART szoftvveres triggerelés ALIGN jobbra/balra igazítás DMA DMA mód engedélyezés CONT folyamatos mód ADON ADC bekapcsolás 9
Az ADC fontosabb regiszterei ADC_SMPR1/ADC_SMPR2 ADC mintavételezési idő megadása 10
Az ADC fontosabb regiszterei ADC_SQR1 - SQR3 ADC szekvenciák megadása 11
Program07_1 Az STM32F103C8 mikrovezérlő AN1 (PA1) analóg bemenetére kötötti potméter csúszkáról levetti feszültséget mérjük A konverziót az ADC1_CR2 regiszterben a SWSTART bit 1-be állításával indítjuk, külső triggerjel forrásként kell konfingurálni Az eredménytől függően (ha a 8. bit = 1), akkor kigyújtjuk a beépítetti LED-et, egyébként pedig leoltjuk 12
Program07_1/main.c #include "stm32f10x.h" int main (void) { int result; //--- PC13, a beépített LED konfigurálása -------- RCC->APB2ENR = RCC_APB2ENR_IOPCEN; // GPIOC órajel engedélyezés GPIOC->CRH &= ~(GPIO_CRH_CNF13 GPIO_CRH_MODE13); // pin13 CNF/Mode bitek törlése GPIOC->CRH = GPIO_CRH_MODE13_1; // CNF:00, Mode:10 PPout, 2MHz GPIOC->BSRR = GPIO_BSRR_BS13; // GPIOC 13. bitset (LED ki) //--- PA1 analóg bemenet konfigurálása ----------- RCC->APB2ENR = RCC_APB2ENR_IOPAEN; // GPIOA engedélyezés GPIOA->CRL &= ~GPIO_CRL_MODE1; // PA1 analóg bemenet GPIOA->CRL &= ~GPIO_CRL_CNF1; // CNF=00, Mode=00 //--- ADC1 konfigurálása ------------------------- RCC->APB2ENR = RCC_APB2ENR_ADC1EN; // ADC1 órajel engedélyezés RCC->CFGR &= ~RCC_CFGR_ADCPRE_0; // ADC prescaler = 6 RCC->CFGR = RCC_CFGR_ADCPRE_1; // ADCCLK = 72/6 = 12 MHz ADC1->CR2 = ADC_CR2_EXTTRIG // External trigger engedélyezés ADC_CR2_EXTSEL; // EXTSEL=111 SW trigger választása ADC1->SQR3 = 1; // Ch 1-gyel indul a konverziós sorozat ADC1->SQR1 = 0; // A konverzió sorozat hossza = 1 ADC1->CR2 = ADC_CR2_ADON; // ADC1 engedélyezése 13
Program07_1/main.c } while (1) { ADC1->CR2 = ADC_CR2_SWSTART; while(!(adc1->sr & ADC_SR_EOC)); result = ADC1->DR; if (result & 0x100) GPIOC->BSRR = GPIO_BSRR_BR13; else GPIOC->BSRR = GPIO_BSRR_BS13; } // Konverzió indítása // Konverzió végére várunk // Az eredmény kiolvasása (törli az EOC bitet!) // Ha bit8 = 1, akkor // LED be // különben // LED ki 14
Program07_2 Az STM32F103C8 mikrovezérlő belső hőmérőjének (AN16) jelét mérjük és számítjuk át Celsius fokokra A konverziót Timer2 CH2 csatornájának CC2 eseményével (PWM1 módban CNT = CCR2 egyezés) keltjük, 1 másodpercenként Az eredményt az UART1 soros porton (RB6) kiíratjuk, az előző előadás uart_irq mintapéldájában bemutatotti módon 15
#include "stm32f10x.h" #include <stdio.h> extern void buffer_init (void); extern void USART1_init (void); void Timer2_Init(void); void ADC1_Init(void); void GPIO_Init(void); Program07_2/main.c A kiíratáshoz kellenek int main (void) { int data; double volt, temp; buffer_init(); // RX / TX bufferek inicializálása USART1_init(); // USART1 configuration Timer2_Init(); // TIM2 konfigurálás: 1 Hz trigger ADC1_Init(); // ADC1 konfigurálás belsö homerohöz enable_irq(); // Megszakítások globális engedélyezése printf("adc internal temperature sensor \r\n"); while (1) { // végtelen ciklus while(!(adc1->sr & ADC_SR_EOC)); // Konverzió végére várunk data = ADC1->DR; /* Temperature (in C) = {V25 - VSENSE ) / Avg_Slope} + 25 */ /* V25 = 1.41V, slope = 4.5 mv/c */ volt = (double)data*3.3 / 4096; /* convert ADC output to voltage */ temp = (1.41 - volt) / 0.0045 + 25; /* convert voltage to temperature C */ printf("%d, %.2f C\r\n", data, temp); } } 16
Program07_2/main.c /*------------------------------------------------- TIMER2 CH2 konfigurálása 1 Hz-es triggereléshez -------------------------------------------------*/ void Timer2_Init() { RCC->APB1ENR = RCC_APB1ENR_TIM2EN; // TIM2 órajel engedélyezése TIM2->CR1 = 0; TIM2->CR2 = 0; TIM2->PSC = SystemCoreClock/10000-1; // 10 khz-re osztjuk le az órajelet TIM2->ARR = 10000-1; // 1000-ig számlálunk (1000 ms) TIM2->CNT = 0; // Számláló nullázása TIM2->CCMR1 = 0x6800; // Ch2 PWM1 mód, preload enable TIM2->CCER = TIM_CCER_CC2E; // Ch2 engedélyezése TIM2->CCR2 = 50-1; TIM2->CR1 = TIM_CR1_CEN; // Számlálás engedélyezés } OC2M = 110 PWM1 mód, OC2PE = 1 Preload register enable, CC2S = 00 output mode 17
Program07_2/main.c void ADC1_Init() { RCC->APB2ENR = RCC_APB2ENR_ADC1EN; // ADC1 órajel engedélyezés RCC->CFGR &= ~RCC_CFGR_ADCPRE_0; // ADC prescaler = 6 RCC->CFGR = RCC_CFGR_ADCPRE_1; // ADCCLK = 72/6 = 12 MHz ADC1->CR1 = 0; ADC1->CR2 = ADC_CR2_EXTTRIG // External trigger engedélyezés ADC_CR2_EXTSEL_0 // EXTSEL=011, TIM2 CC2 event ADC_CR2_EXTSEL_1; ADC1->SMPR1 = ADC_SMPR1_SMP16; // 111: Mintavétel 239.5 ciklus ADC1->SQR3 = 16; // Ch 16. a belsö hömérö ADC1->SQR1 = 0; // A konverzió sorozat hossza=1 ADC1->CR2 = ADC_CR2_ADON // ADC1 engedélyezése ADC_CR2_TSVREFE; // A hömérö bekapcsolása } EXTSEL= 011 Timer2 CC2 event, EXTTRIG=1 triggering enable, ALIGN=0 jobbra igazítás CONT=0 single conversion mode, ADON=1 ADC power ON 18
Program07_2 futási eredmény A 72 MHz-en futó MCU a kiírás szerint elég melegnek tűnik, de vegyük fingyelembe, hogy a hőmérő nincs kalibrálva 19
20