[3] JAVA i STM32 – ekspresowy kurs programowania z MicroEJ – obsługa ADC i DAC
List. 6. Kod metody main
public static void main(String[] args) { DAC dac = new DAC(); ADC adc = new ADC(); dac.init(); adc.init(); MWT.RenderingContext.add(new PlainTheme()); Desktop desktop = new Desktop(); Panel panel = new Panel(); GridComposite gc = new GridComposite(MWT.VERTICAL, 4); TitleLabel title = new TitleLabel("ADC/DAC EXAMPLE"); title.setFontSize(LookExtension.GET_X_BIG_FONT_INDEX); gc.add(title); FlowComposite fcDac = new FlowComposite(); TitleLabel labelDacTitle = new TitleLabel("Dac Value [mV]:"); fcDac.add(labelDacTitle); TextField dacValueField = new TextField("--------"); fcDac.add(dacValueField); Scale scaleDac = new Scale(0, 300); scaleDac.setListener(new DACScaleListener(dacValueField, dac)); fcDac.add(scaleDac); gc.add(fcDac); FlowComposite fcAdc = new FlowComposite(); TitleLabel labelAdcTitle = new TitleLabel("ADC Value [mV]:"); fcAdc.add(labelAdcTitle); TextField adcValueField = new TextField("--------"); fcAdc.add(adcValueField); Button buttonAdc = new Button("Get ADC value"); buttonAdc.setListener(new ADCButtonListener(adcValueField, adc)); fcAdc.add(buttonAdc); gc.add(fcAdc); panel.setWidget(gc); panel.show(desktop, true); desktop.show(); }
Wystarczy już tylko utworzyć nową konfiguracją z opcją Execute on EmbJPF, aby aplikacja była gotowa do zaprogramowania w pamięci mikrokontrolera.
Obsługa przetworników (C)
Przed uruchomieniem aplikacji trzeba jeszcze dokonać zmian w BSC dodając obsługę przetworników. Po uruchomieniu projektu w środowisku uVision należy utworzyć dwa nowe pliki adc.c i dac.c zawierające implementacje zadeklarowanych w Javie funkcji kontroli przetworników. Funkcje te pokazano na listingach 7 i 8.
List. 7. Implementacja funkcji inicjalizacji i pobrania wartości przetwornika analogowo-cyfrowego
void Java_app_ADC_ADCInit(void) { printf("ADC init\n"); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOC, &GPIO_InitStructure); ADC_CommonInitTypeDef ADC_CommonInitStructure; ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; ADC_CommonInit(&ADC_CommonInitStructure); ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left; ADC_InitStructure.ADC_NbrOfConversion = 1; ADC_Init(ADC3, &ADC_InitStructure); ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 1, ADC_SampleTime_3Cycles); ADC_Cmd(ADC3, ENABLE); } int Java_app_ADC_ADCGetValue(void) { printf("ADC get value\n"); ADC_SoftwareStartConv(ADC3); while(ADC_GetFlagStatus(ADC3, ADC_FLAG_EOC) == RESET) __NOP(); ADC_ClearFlag(ADC3, ADC_FLAG_EOC); uint32_t data = ADC_GetConversionValue(ADC3) >> 4; data = data * 3000/4096; return (int)data; }
List. 8. Implementacja funkcji inicjalizacji i ustawiania wartości przetwornika cyfrowo-analogowego
void Java_app_DAC_DACInit(void) { printf("DAC init\n"); RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure); DAC_InitTypeDef DAC_InitStructure; DAC_InitStructure.DAC_Trigger = DAC_Trigger_None; DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; DAC_Init(DAC_Channel_2, &DAC_InitStructure); DAC_Cmd(DAC_Channel_2, ENABLE); DAC_SetChannel2Data(DAC_Align_12b_L, 0x0); } void Java_app_DAC_DACSetValue(int value) { printf("DAC set value %d\n", value); uint32_t data = value * 4095 / 3000; DAC_SetChannel2Data(DAC_Align_12b_R, (uint16_t)data); }
Na pierwszy rzut oka można zauważyć charakterystyczne nazwy wszystkich czterech funkcji. Z uwagi na to, że są one wywoływane z kodu Javy, muszą one mieć w swojej nazwie pełną ścieżkę do swoich deklaracji w aplikacji z uwzględnieniem pakietów i klas w których się one znajdują. Poza nazwani, nie odbiegają niczym od funkcji znanych z przykładów biblioteki STM32 Standard Peripheral Library. Funkcje konfiguracyjne inicjalizują sygnały zegarowe dla swoich peryferii oraz przypisanych im portów GPIO (PC3 dla ADC i PA5 dla DAC) wypełniają struktury inicjalizacyjne. Funkcja odczytująca wartość ADC nie wykorzystuje przerwań, lecz po uruchomieniu konwersji czeka na jej zakończenie sygnalizowane odpowiednią flagą.
Projekt można teraz skompilować i zaprogramować pamięć mikrokontrolera. Po każdym odwołaniu do funkcji C, w konsoli debugowania (Debug (printf) Viewer) można zaobserwować logi wyświetlane przez poszczególne funkcje.