Дя синхронізації роботи АЦП використаємо таймери мікроконтролера AT91SAM3X8E. Він має 3 лічильника таймера (TC): TC0, TC1, TC2.
Кожен лічильник таймера містить 3 канали з нумерацією 0, 1 і 2 (разом - 9 каналів). Кожен канал має свої власні лічильники і обробник переривань, які не залежать від інших каналів, іншими словами, кожен канал може розглядатися як окремий "таймер".
Щоб ініціалізувати канал, потрібні такі параметри:
TC0 / TC1 / TC2 - Номер таймера
0/1/2 - Номер каналу в лічильнику таймера
Таймерам "відповідають" контакти Arduino DUE. Так, використаному в прикладі таймеру TC0 на каналі 0 відповітають контакти 2 (порт В.25) та 13 (порт В.27).
Таймери можуть тактуватись частотою, що кратна /2,/8,/32,/128 від робочої частоти мікроконтролера:
TIMER_CLOCK1: 84Mhz/2 = 42.000 MHz
TIMER_CLOCK2: 84Mhz/8 = 10.500 MHz
TIMER_CLOCK3: 84Mhz/32 = 2.625 MHz
TIMER_CLOCK4: 84Mhz/128 = 656.250 KHz
В результаті у нас АЦП буде 2 рази на секунду міряти напругу на вході А0 і переключатись інтегрований світлодіод на 13 виході з частотою 1 Гц.
Для тих, хто хоче самостійно внести деякі зміни в скетч для "самопровірки" роботи АЦП:
Код: Виділити все
/*Додамо ще одну змінну*/
volatile boolean bolTact = false;
...
/*Підключемо послідовний порт та контакт 2 (порт В.25) замість 13*/
Serial.begin(115200);
PIOB->PIO_OER = 1 << 25;
...
/*Кожен такт будемо виводити заміряну напругу на монітор послідовного порту*/
if (bolTact)
{
bolTact = false;
Serial.println(intResultA0);
}
...
/*В обробнику переривань також замінимо 13 контакт на 2*/
REG_PIOB_ODSR ^= 1 << 25;
Код: Виділити все
#define ADC_REFERENCE_VALUE (3.3)
#define ADC_12BIT_FULL_SCALE_VALUE (4095)
volatile int intResultA0;
volatile boolean bolTact = false;
void setup()
{
Serial.begin(115200);
PIOB->PIO_OER = 1 << 25; // Встановлюємо 2 контакт Arduino DUE як вихід
adc_setup(); // АЦП
tc_setup(); // Таймер
}
void loop()
/*Виводимо виміряну напругу на монітор послідовного порту*/
{
if (bolTact)
{
bolTact = false;
Serial.println(intResultA0);
}
}
/*Configure ADC function*/
void adc_setup()
{
PMC->PMC_PCER1 |= PMC_PCER1_PID37;
ADC->ADC_CR = ADC_CR_SWRST;
ADC->ADC_MR |= ADC_MR_TRGEN_EN |
ADC_MR_TRGSEL_ADC_TRIG1 |
ADC_MR_LOWRES_BITS_12 |
ADC_MR_SLEEP_NORMAL |
ADC_MR_PRESCAL(1) |
ADC_MR_STARTUP_SUT0 |
ADC_MR_SETTLING_AST9 |
ADC_MR_ANACH_ALLOWED |
ADC_MR_TRACKTIM(10) |
ADC_MR_TRANSFER(2) |
ADC_MR_USEQ_NUM_ORDER;
ADC->ADC_COR = ADC_COR_OFF7;
ADC->ADC_IER = ADC_IER_EOC7;
NVIC_EnableIRQ(ADC_IRQn);
ADC->ADC_CHER = ADC_CHER_CH7;
}
/* Timer Counter 0 Channel 0 to generate PWM pulses thru TIOA0 */
void tc_setup()
{
PMC->PMC_PCER0 |= PMC_PCER0_PID27;
TC0->TC_CHANNEL[0].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1
| TC_CMR_WAVE
| TC_CMR_WAVSEL_UP_RC
| TC_CMR_ACPA_CLEAR
| TC_CMR_ACPC_SET;
TC0->TC_CHANNEL[0].TC_RC = 21000000;
TC0->TC_CHANNEL[0].TC_RA = 10500000; // Від 1 до 20999999
TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN;
}
/* Обробка переривань */
void ADC_Handler(void)
{
intResultA0 = ADC->ADC_CDR[7];
REG_PIOB_ODSR ^= 1 << 25; //переключити (інвертувати) рівень 2 виходу
bolTact = true;
}
Зверніть увагу:
PS. Для тих, хто не використовує ардуіно, але хоче ознайомитись з кодом, в архів додадано його лістинг в форматі .docст. 1403 дадашиту
1. Use ADC_ACR.IBCTL = 00 for sampling frequency below 500 kHz.
2. Use ADC_ACR.IBCTL = 01 for sampling frequency between 500 kHz and 1 MHz.