[STemWIN] Cyfrowy magnetometr na STM32 z graficzną prezentacją wyników
Po uruchomieniu układu wykonywanie programu rozpoczyna się od głównej funkcji main(), w której konfigurowane są peryferia (przycisk, przetwornik A/C), tworzone jest nowe zadanie Magnetometer oraz wywoływany jest planista (scheduler) systemu FreeRTOS.
int main(void){
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
/* Configure USER button */
STM_EVAL_PBInit(BUTTON_USER, BUTTON_MODE_GPIO);
/* Configure ADC */
ADC_Config();
/* Create main task */
xTaskCreate(Main_Task,
(signed char const*)"Magnetometer",
Main_Task_STACK,
NULL,
Main_Task_PRIO,
&Task_Handle);
/* Launch Touchscreen Timer */
TouchScreenTimer = xTimerCreate ((signed char *)"Timer", 50, pdTRUE, (void*) 1, vTimerCallback);
if( TouchScreenTimer != NULL )
{
if( xTimerStart( TouchScreenTimer, 0 ) != pdPASS )
{
/* The timer could not be set into the Active state. */
}
}
/* Start the FreeRTOS scheduler */
vTaskStartScheduler();
return 0;
}
Przetwornik A/C jest skonfigurowany do pracy z 13 kanałem (nóżka PC3), a pojedynczy pomiar wyzwalany jest programowo w funkcji adc_convert():
static void ADC_Config(void){
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable ADC interface clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
/* Enable GPIOC clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
/* Configure ADC pin */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* Reset ADC */
ADC_DeInit();
/* Configure ADC - common settings */
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_20Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
/* Configure ADC - settings for ADC1 */
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = 0;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);
/* Activate ADC */
ADC_Cmd(ADC1, ENABLE);
/* Select channel ADC123_IN13 (PC3 pin) */
ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 1, ADC_SampleTime_144Cycles);
}
uint16_t adc_convert(){
// Start conversion of regular channel
ADC_SoftwareStartConv(ADC1);
// Wait until end of conversion
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
// Return converted data
return ADC_GetConversionValue(ADC1);
}
Zadanie o nazwie Magnetometer realizuje funkcja Main_Task(). Pierwsza rzecz jaka jest wykonywana w tym zadaniu to inicjalizacja warstwy BSP oraz biblioteki STemWin, a dopiero po tym tworzone są widżety FRAMEWIN, GRAPH i TEXT.
static void Main_Task(void * pvParameters){
unsigned int ticks = 0;
// Deklaracja uchwytów
FRAMEWIN_Handle hFrame, hClientWin;
GRAPH_Handle hGraph;
GRAPH_DATA_Handle hGraphData;
GRAPH_SCALE_Handle hGraphScale;
TEXT_Handle hText_1, hText_2, hText_3, hText_4;
uint16_t conversion_value;
double voltage_mV, voltage_V;
double magneticField_G, magneticField_mT;
char text[100];
// Inicjalizacja warstwy BSP
LowLevel_Init();
// Inicjalizacja biblioteki STemWin GUI
GUI_Init();
// Ustawienie koloru tła na jasnoniebieski
WM_SetDesktopColor(GUI_LIGHTBLUE);
// Ustawienie stylu FLEX dla widżetu FRAMEWIN
FRAMEWIN_SetDefaultSkin(FRAMEWIN_SKIN_FLEX);
// Utworzenie widżetu FRAMEWIN
hFrame = FRAMEWIN_CreateEx(10, 30, 220, 230, WM_HBKWIN, WM_CF_SHOW, 0, 0, "Magnetometer", NULL);
hClientWin = WM_GetClientWindow(hFrame); // Pobranie uchwytu do obszaru klienta
FRAMEWIN_SetFont(hFrame, &GUI_Font16_ASCII); // Ustawienie czcionki tekstu na pasku tytułowym
FRAMEWIN_SetTextAlign(hFrame, GUI_TA_HCENTER); // Wyśrodkowanie tekstu na pasku tytułowym
// Utworzenie i konfiguracja widżetu GRAPH
hGraph = GRAPH_CreateEx(5, 5, 200, 120, hClientWin, WM_CF_SHOW, 0, GUI_ID_GRAPH0);
GRAPH_SetBorder(hGraph, 40, 0, 0, 0); // Ustawienie szerokości 40 px lewego obramowania
GRAPH_SetGridDistY(hGraph, 15); // Odstęp 15 px między poziomymi liniami siatki
GRAPH_SetGridOffY(hGraph, 10); // Przesunięcie siatki o 10 px w górę
GRAPH_SetGridVis(hGraph, 1); // Uwidocznienie siatki
GRAPH_SetLineStyleH(hGraph, GUI_LS_DOT); // Poziome linie siatki w stylu kropkowanym
GRAPH_SetLineStyleV(hGraph, GUI_LS_DOT); // Pionowe linie siatki w stylu kropkowanym
GRAPH_SetUserDraw(hGraph, _UserDraw); // Wskazanie funkcji rysującej dodatkowe elementy na wykresie
// Utworzenie zbioru danych o pojemności do 200 próbek
hGraphData = GRAPH_DATA_YT_Create(GUI_GREEN, 200, NULL, 0);
GRAPH_DATA_YT_SetOffY(hGraphData, 10); // Przesunięcie danych na wykresie o 10 px w górę
// Dołączenie zbioru danych do widżetu GRAPH
GRAPH_AttachData(hGraph, hGraphData);
// Utworzenie skali osi pionowej z krokiem co 30 px i tekstem wyrównanym do prawej
hGraphScale = GRAPH_SCALE_Create(38, GUI_TA_RIGHT, GRAPH_SCALE_CF_VERTICAL, 30);
GRAPH_SCALE_SetFactor(hGraphScale, 0.033); // Przeliczenie wartości na skali z [px] na [V]
GRAPH_SCALE_SetNumDecs(hGraphScale, 1); // Ustawienie liczby cyfr wyświetlanych po przecinku
GRAPH_SCALE_SetOff(hGraphScale, 10); // Przesunięcie skali na wykresie o 10 px w górę
GRAPH_SCALE_SetTextColor(hGraphScale, GUI_BLACK); // Wybranie koloru tekstu na skali
// Dołączenie skali do widżetu GRAPH
GRAPH_AttachScale(hGraph, hGraphScale);
// Utworzenie widżetów TEXT
hText_1 = TEXT_CreateEx(10, 140, 100, 20, hClientWin, WM_CF_SHOW, TEXT_CF_LEFT, GUI_ID_TEXT0, "[V]");
hText_2 = TEXT_CreateEx(10, 160, 100, 20, hClientWin, WM_CF_SHOW, TEXT_CF_LEFT, GUI_ID_TEXT1, "[G]");
hText_3 = TEXT_CreateEx(10, 180, 100, 20, hClientWin, WM_CF_SHOW, TEXT_CF_LEFT, GUI_ID_TEXT2, "[mT]");
hText_4 = TEXT_CreateEx(160, 160, 20, 20, hClientWin, WM_CF_SHOW, TEXT_CF_LEFT, GUI_ID_TEXT3, " ");
TEXT_SetFont(hText_4, &GUI_Font20_ASCII);
// Wybranie/Zaznaczenie okna głównego
WM_SetFocus(hFrame);
// Wykonanie zadania głównego
while(1){
if(ticks++ > 5){
ticks = 0;
// Inwersja LED3 co 50ms
STM_EVAL_LEDToggle(LED3);
// Odczyt nowych danych z czujnika
conversion_value = adc_convert();
// Konwersja 12-bitowej wartości na [V]
voltage_mV = (double)conversion_value * 0.7324;
voltage_V = voltage_mV / 1000.0;
// Konwersja na gaussy [G] oraz minitesle [mT]
magneticField_G = (voltage_mV - 1500) / A1395_SENSITIVITY;
magneticField_mT = magneticField_G / 10.0;
// Przeskalowanie i dodanie nowej próbki do zbioru danych widżetu GRAPH
GRAPH_DATA_YT_AddValue(hGraphData, 30*voltage_V);
// Aktualizacja tekstu widżetów TEXT
sprintf(text,"V = %.3f [V]", voltage_V);
TEXT_SetText(hText_1, text);
sprintf(text,"B = %.3f [G]", magneticField_G);
TEXT_SetText(hText_2, text);
sprintf(text,"B = %.3f [mT]", magneticField_mT);
TEXT_SetText(hText_3, text);
// Wyświetlenie biegunowości pola magnetycznego
if(magneticField_G > 5.0){
TEXT_SetText(hText_4, "N");
TEXT_SetTextColor(hText_4, GUI_BLUE);
}
else if(magneticField_G < -5.0){
TEXT_SetText(hText_4, "S");
TEXT_SetTextColor(hText_4, GUI_RED);
}
else{
TEXT_SetText(hText_4, " ");
}
}
GUI_Delay(10);
}
// Usunięcie widżetów
WM_DeleteWindow(hGraph);
WM_DeleteWindow(hFrame);
}

Technologie End of Life i bezpieczeństwo sieci – wyzwania Europy związane z tzw. długiem technologicznym
Najczęstsze błędy firm przy wyborze dostawcy energii i jak ich uniknąć
Fotorezystor, czyli czujnik światła dwojakiego działania. Przykład innowacji w automatyce i elektronice możliwej dzięki technologii fotooporników 



