andrade Postat Decembrie 2, 2017 Partajează Postat Decembrie 2, 2017 Mie imi place Attolic. Inca o data, multumesc pentru informatii si tutorial. In cateva zile fac primele incercari si voi urmari indicatiile furnizate de tine. Link spre comentariu
nico_2010 Postat Decembrie 15, 2017 Autor Partajează Postat Decembrie 15, 2017 Salut din nou!Astazi este ultima postare pe acest subiect pentru 2017 si are ca subiect utilizarea unui timer in regim de intreruperi.Pentru asta urmati primii doi pasi din postarea#1 si faceti selectia asa cum este prezentata in figura de mai jos (foto blink_settings): Odata terminate selectiile de mai sus, alegem tab-ul Clock settings (foto blink_clock_settings) si setam valoarea oscilatorului extern HSE la 8MHz, si HCLK la 72MHz, asa cum este prezentat in fotografia de mai jos In continuare vom seta TIM1 ca in figura de mai jos (foto blink_TIM1_settings): si activam in tab-ul NVIC (Nested Vectored Interrupt Controller) TIM1 update interrupt, ca mai jos: Salvam proiectul intr-un folder nou aflat in folderul "Workspace" si generam proiectul pe care, ulterior, il vom deschide selectand butonul 'Open project". In acest moment avem un fisier "main" care contine aproape toate setarile care sa ne permita sa aprindem si sa stingem un led cu o anumita perioada. Timerul TIM1 este setat pentru functionare in regim free-runing, astfel ca, dupa activare va incepe sa numere cu o frecventa data de propriul ceas (F_clk/Prescaler), iar cand ajunge la valoarea inscrisa in Period are loc depasirea capacitatii sale de numarare (overflow) si va genera un eveniment de tip Update event (o intrerupere) si procesul de numarare se reia de la zero.Si totusi trebuie sa ne aducem contributia, astfel ca vom include urmatoarele linii de comanda in fisierul "main": /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_TIM1_Init(); /* USER CODE BEGIN 2 */ HAL_TIM_Base_Start_IT(&htim1);//--> Comanda porneste TIM1 in regim free-runing si permite generarea de intreruperi /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ si aceasta rutina, care trateaza intreruperea : void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (__HAL_TIM_GET_FLAG(&htim1,TIM_FLAG_UPDATE) != RESET) { __HAL_TIM_CLEAR_IT(&htim1,TIM_IT_UPDATE); } HAL_GPIO_TogglePin(MyLED_GPIO_Port, MyLED_Pin); } Dupa compilare si incarcarea fisierului hex in uC ledul conectat la pinul PC13 va pulsa cu o frecventa de aproximativ 5 Hz (frecventa cu care este accesata rutina HAL_TIM_PeriodElapsedCallback este de aprox. 10Hz), conform formulei: Promit sa nu va mai plicitisesc anul asta cu asa ceva! main.txt Link spre comentariu
mars01 Postat Decembrie 28, 2017 Partajează Postat Decembrie 28, 2017 Felicitari Nico pentru tutorial! Cat de curand o sa contribui si eu pe sectiunea aceasta cu una-alta. Sarbatori fericite! Link spre comentariu
nico_2010 Postat Decembrie 29, 2017 Autor Partajează Postat Decembrie 29, 2017 Multumesc pentru aprecieri. Si tu si altii sunteti bineveniti cu diferite contributii la topic. Sarbatori fericite! Link spre comentariu
Galagie Postat Decembrie 31, 2017 Partajează Postat Decembrie 31, 2017 (editat) Felicitari pentru initiativa, imi place ca lucrurile pe forum mai evolueaza de la pic/atmel si pe chestii mai profi Am parasit si eu de vreo 3 ani familile pe 8 biti, si am trecut brusc la 32biti pe un stm32f407 ( discovery f4board), prima saptamana a fost crunta cu acomodarea De atunci doar cu stm32f103 si stm32f4xx lucrez. Personal incerc sa stau departe de librariile HAL, inca le folosesc pe cele "non-hall", se gasesc multe informatii si tutoriale cu ele, dar tine de gustul fiecaruia Ai grija la timere, clock-ul timerului este dat de AHPB_clock / prescaler, la timere acel AHPB dupa derivare din HCLK este dublat. Pe HAL nu stiu daca poti folosi urmatoarele linii de cod RCC_ClocksTypeDef clocks; RCC_GetClocksFreq(&clocks); Cu astea in debuger poti sa vezi valorile reale ale clock-urilor, pe mine m-a scos de cateva ori din belele Editat Decembrie 31, 2017 de Galagie Link spre comentariu
nico_2010 Postat Ianuarie 1, 2018 Autor Partajează Postat Ianuarie 1, 2018 LA MULTI ANI! Multumesc pentru aprecieri. Este optiunea fiecaruia de a alege SPL sau HAL. Eu am ales HAL pentru simplul motiv ca ST nu mai ofera suport tehnic pentru SPL. Cum scheletul proiectului este generat de CubeMX, grijile referitoare la semnalul de ceas aferent bunei functionari a timerelelor dispar, intrucat inca de la inceput utilizatorul va sti ce frecventa va avea ceasul pentru un anumit timer (are imaginea clara in fereastra de "Clock settings"). Link spre comentariu
nico_2010 Postat Ianuarie 19, 2018 Autor Partajează Postat Ianuarie 19, 2018 In sfarsit a aparut versiunea 9.0 a Atollic True Studio: https://atollic.com/resources/download/windows/windows-archive/?submissionGuid=e68f10b0-8cff-4387-9a45-b45da67379f0 Un plus este ca noua versiune este Pro si nu Lite, asta inseamnand ca toate facilitatile sunt deblocate si este free. Un minus (minor pentru utilizatori ca mine) este ca functioneaza doar pentru microcontrollere-le din seria STM32 ( nu ca pana acum pentru toate microcontrollerele ARM). Vom vedea in viitor cum se comporta. Link spre comentariu
nico_2010 Postat Februarie 2, 2018 Autor Partajează Postat Februarie 2, 2018 Daca ar fi sa ma iau dupa numarul de vizualizari al acestui topic ajung la concluzia ca totusi ceva interes prezinta. Si totusi... cu cateva exceptii, nimeni nu prea este interesat de acest tip de microcontrollere (mult mai "interesant" este razboiul orgoliilor din alte sectiuni!). Sunt constient de faptul ca modul de prezentare al tutorialului poate lasa putin de dorit: prea putina vorbarie, fara prea multe explicatii de ce asa si nu altfel! Am considerat insa ca imaginile fac mai mult decat o mie de cuvinte (jur ca nu este intentia mea sa plagiez pe cineva pentru aceasta expresie). In plus, postarea proiectului in integralitate (cu mici exceptii) poate servi ca baza de plecare pentru studiu mai aprofundat. OK, sa depasim momentul! Astazi va prezint o facilitate interesanta a timerelor de uz general si a celor avansate ce fac parte din structura STM32, mai precis de functia One Pulse Mode (OPM). Aceasta functie este un mix intre functiile de "Input Capture" si "Output Compare" oferite de categoria mentionata de timere si permite acestora sa inceapa functionarea ca raspuns la un stimul extern, cu o anumita intarziere si pentru o anumita durata. OPM este proiectata pentru a folosi exclusiv canalele "Channel 1" si "Channel 2" ale timerului, acestea putand fi selectate folosind functia: HAL_TIM_OnePulse_ConfigChannel(TIM_HandleTypeDef *htim, TIM_OnePulse_InitTypeDef* sConfig, uint32_t OutputChannel, uint32_t InputChannel); N.B: Timerul trebuie sa functioneze in regim "Slave mode", iar sursa de trigger-are sa fie TI1FP1 (aferenta Channel 1) sau TI2FP2 (aferenta Channel 2) depinde de canalul selectat ca intrare , in caz contrar functia OPM nu lucreaza! Calculul intarzierii la pornire este dat de formula: Iar calculul duratei impulsului este dat de formula: Pentru setari, urmati primii doi pasi din postarea#1 si faceti selectia asa cum este prezentata in figura de mai jos (foto settings): Selectati frecventa ceasului intern, ca mai jos (foto: clock_settings): Pasul urmator este configurarea timerului (eu am ales TIM1), ca in fotografia de mai jos: Si binenteles configurarea NVIC (am vorbit despre asta in postrea precedenta): Generam proiectul si obtinem astfel proiectul cu setarile de baza (in stare de reset a microcontroller-ului). Ne aducem si noi contributia cu ceva, inserand cele doua comenzi de mai jos, in pozitia corespunzatoare: int main(void) { /* MCU Configuration----------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_TIM1_Init(); /*Aici sunt introduse cele doua comenzi de pornire a timerului */ /* USER CODE BEGIN 2 */ HAL_TIM_Base_Start_IT(&htim1); HAL_TIM_OnePulse_Start_IT(&htim1, TIM_CHANNEL_2); /* USER CODE END 2 */ while (1) { } } Compilam fisierul si il incarcam in microcontroller. Conectam un buton la portul PA.8 si GND si un LED, printr-o rezistenta de 100 ohm, la portul PA.9 si vizualizam rezultatul muncii: de fiecare data cand apasam butonul dupa o anumita intarzire (in cazul nostru de circa 3 secunde) LED-ul se va aprinde o anumita durata de timp (in acest caz circa 2 secunde) apoi se stinge. Aveti atasat fisierul main si incerc sa postez si proiectul integral. main.txt Link spre comentariu
nico_2010 Postat Februarie 5, 2018 Autor Partajează Postat Februarie 5, 2018 Si proiectul complet. OPM_F103_TIM1.zip Link spre comentariu
nico_2010 Postat Octombrie 19, 2018 Autor Partajează Postat Octombrie 19, 2018 (editat) M-am decis sa continui cu acest mic tutorial, incurajat fiind doar de numarul mare de vizualizari.Cat despre reactii ... cateva, raportate la numarul de vizualizari. Sper totusi ca ceea ce prezint aici, asa, in stilul meu mai putin pedagogic, sa foloseasca celor care vor sa invete despre aceste microcontrollere puternice si foarte versatile. In continuare ramanem cantonati la timere si voi prezenta o modalitate de a genera semnal sinusoidal folosind functia de generator de PWM (STM32F103C8T6 nu dispune de DAC). Ideea de baza este aceea de a genera pulsuri cu latimea variabila care, prin filtrare, sa duca la obtinerea unui semnal sinusoidal. Pentru asta apelam la tehnica DDS, conceptul de baza fiind de a calcula faza la fiecare moment de eșantionare. În general, pentru o frecvență arbitrară de eșantionare Fsample și frecvența dorita Fout, faza trebuie să crească cu R = 2 * pi * ( Fout/Fsample) la fiecare moment de eșantionare. Pentru setari, urmati primii doi pasi din postarea#1 si faceti selectia asa cum este prezentata in figura de mai jos: Dupa cum se vede am selectat pentru aceasta aplicatie timerul TIM2 si canalul 1 al acestuia pentru generarea de semnal PWM. Selectam tab-ul "Clock Configuration" si facem setarile pentru semnalul de ceas, ca mai jos: Pasul urmator ar fi, in mod normal sa configuram Timer-ul 2 pentru functia de generare a semnalului PWM, asa ca selectam tab-ul "Configuration" si procedam in felul urmator: - Selectam butonul "TIM2" si se deschide fereastra de configurare propriu-zisa. La sectiunea "PWM Generation Channel 1", in dreptul setarii "Mode" alegeti "PWM mode 1" din fereastra defilanta si apasati butonul "Apply" (vezi mai jos) Selectati tabul "NVIC Settings" si vom bifa in noua fereastra "TIM2 Global Interrupt", asta pentru avem nevoie ca timerul sa lucreze in regim de intreruperi. In final setam portul de iesire sa functioneze in regim de push-pull si cu o viteza maxima: Salvam totul sub un nume convenabil si generam proiectul, care, asa cum am mai spus, va contine doar setarile in stare de reset ale microcontroller-ului. Acesta este fisierul "main.c", asa cum este generat de CubeMX si completat de mine cu variable si alte cele necesare functionarii proiectului. /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** ** This notice applies to any and all portions of this file * that are not between comment pairs USER CODE BEGIN and * USER CODE END. Other portions of this file, whether * inserted by the user or by software development tools * are owned by their respective copyright owners. * * COPYRIGHT(c) 2018 STMicroelectronics * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of STMicroelectronics nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "stm32f1xx_hal.h" /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private variables ---------------------------------------------------------*/ TIM_HandleTypeDef htim2; /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ #define POW232 4294967296 //valoarea 2^32 uint16_t sinetable[] = { 256, 262, 269, 275, 281, 287, 294, 300, 306, 312, 318, 324, 330, 336, 342, 348, 354, 360, 365, 371, 377, 382, 388, 393, 398, 403, 408, 413, 418, 423, 428, 433, 437, 441, 446, 450, 454, 458, 462, 465, 469, 472, 476, 479, 482, 485, 487, 490, 493, 495, 497, 499, 501, 503, 504, 506, 507, 508, 509, 510, 511, 511, 512, 512, 512, 512, 512, 511, 511, 510, 509, 508, 507, 506, 504, 503, 501, 499, 497, 495, 493, 490, 487, 485, 482, 479, 476, 472, 469, 465, 462, 458, 454, 450, 446, 441, 437, 433, 428, 423, 418, 413, 408, 403, 398, 393, 388, 382, 377, 371, 365, 360, 354, 348, 342, 336, 330, 324, 318, 312, 306, 300, 294, 287, 281, 275, 269, 262, 256, 250, 243, 237, 231, 225, 218, 212, 206, 200, 194, 188, 182, 176, 170, 164, 158, 152, 147, 141, 135, 130, 124, 119, 114, 109, 104, 99, 94, 89, 84, 79, 75, 71, 66, 62, 58, 54, 50, 47, 43, 40, 36, 33, 30, 27, 25, 22, 19, 17, 15, 13, 11, 9, 8, 6, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 15, 17, 19, 22, 25, 27, 30, 33, 36, 40, 43, 47, 50, 54, 58, 62, 66, 71, 75, 79, 84, 89, 94, 99, 104, 109, 114, 119, 124, 130, 135, 141, 147, 152, 158, 164, 170, 176, 182, 188, 194, 200, 206, 212, 218, 225, 231, 237, 243, 250, }; #define Fsample 100000 #define Fout 1000 uint32_t r = 0; uint32_t fs = 0; uint32_t fo = 0; float temp = 0; uint16_t pulse_width = 0; uint32_t phase_accumulator = 0; uint8_t angle = 0; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_TIM2_Init(void); void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim); /* USER CODE BEGIN PFP */ /* Private function prototypes -----------------------------------------------*/ /* USER CODE END PFP */ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * * @retval None */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration----------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /*Pentru a genera un semnal PWM - cu frecventa Fsample - care, prin filtrare, sa ne furnizeze un semnal sinusoidal * cu frecventa Fout, vom folosi formula de calcul: R = (2^32) * Fout/Fsample */ fs = Fsample; fo = Fout; temp = (float) (1.0 / (fs / fo)); r = (uint32_t) (POW232 * temp); /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_TIM2_Init(); /* USER CODE BEGIN 2 */ HAL_TIM_Base_Start_IT(&htim2); HAL_TIM_PWM_Start_IT(&htim2, TIM_CHANNEL_1); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; /**Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure the Systick interrupt time */ HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); /**Configure the Systick */ HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); /* SysTick_IRQn interrupt configuration */ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); } /* TIM2 init function */ static void MX_TIM2_Init(void) { TIM_ClockConfigTypeDef sClockSourceConfig; TIM_MasterConfigTypeDef sMasterConfig; TIM_OC_InitTypeDef sConfigOC; htim2.Instance = TIM2; htim2.Init.Prescaler = 0; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 0; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim2) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 0; sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } HAL_TIM_MspPostInit(&htim2); } /** Configure pins as * Analog * Input * Output * EVENT_OUT * EXTI */ static void MX_GPIO_Init(void) { /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @param file: The file name as string. * @param line: The line in file as a number. * @retval None */ void _Error_Handler(char *file, int line) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t* file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ Mai ramane sa adaugam rutina apelata de timerul TIM2 la fiecare intrerupere, in sectiunea USER CODE BEGIN 4 ... USER CODE END 4, respectiv cea de mai jos void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM2) { if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_UPDATE) != RESET) { //resetare flag intrerupere __HAL_TIM_CLEAR_IT(&htim2, TIM_IT_UPDATE); } phase_accumulator += r; angle = (uint8_t) ((phase_accumulator >> 24)); pulse_width = sinetable[angle]; TIM2->CCR1 = pulse_width; //o varianta mai scurta de a trimite la portul de iesire semnalul PWM } } Compilati programul si incarcati-l in microcontroller. Prin conectarea unui filtru trece-jos la portul A0 veti obtine o frumoasa sinusoida. Un exemplu de filtru trece-jos ar fi cel de aici: Cam atat pentru azi. Si proiectul complet. sin_wave_f103.zip L.E.: Am uitat un mic "detaliu" In cadrul rutinei de setare a TIM2, trebuie introdus ce este mai jos: htim2.Init.Period = (SystemCoreClock/fs)-1; in loc de : htim2.Init.Period = 0; In lipsa acestui amanunt nu veti obtine niciun semnal. Editat Octombrie 19, 2018 de nico_2010 Link spre comentariu
nico_2010 Postat Octombrie 19, 2018 Autor Partajează Postat Octombrie 19, 2018 (editat) Si ce obtinem in realitate; Editat Octombrie 19, 2018 de nico_2010 Link spre comentariu
mars01 Postat Octombrie 20, 2018 Partajează Postat Octombrie 20, 2018 (editat) Multumim pentru efortul depus. ARM Cortex este un subiect mai avansat, aceasta justifica tacerea de pe topic Cand te uiti la aproape 1200 de pagini de functii in manualul HAL ... https://www.st.com/content/ccc/resource/technical/document/user_manual/72/52/cc/53/05/e3/4c/98/DM00154093.pdf/files/DM00154093.pdf/jcr:content/translations/en.DM00154093.pdf VisualGDB au unele tutoriale STM32 interesante: https://visualgdb.com/w/tutorials/category/tutorials/embedded/stm32_periph/ Editat Octombrie 20, 2018 de mars01 Link spre comentariu
nico_2010 Postat Octombrie 20, 2018 Autor Partajează Postat Octombrie 20, 2018 Sunt de acord cu tine ca volumul de informatie este mare si descurajant, insa nu cred ca trebuie sa inveti pe dinafara tot manualul. Cred ca accesarea acelor informatii care sa te ajute atunci cand scrii un program (de exemplu, rutina de tratare a intreruperii pentru un timer sau ADC) te scuteste de multe migrene. Ar fi suficient sa dai click pe fisierul care contine functiile pentru gestionarea perifericului respectiv (ex. stm32f1xx_hal_adc.c, stm32f1xx_hal_tim.c) si in fereastra din dreapta a IDE Atollic vei avea toate functiile continute. Link spre comentariu
mars01 Postat Noiembrie 4, 2018 Partajează Postat Noiembrie 4, 2018 (editat) Pretul in FLASH ocupat care se plateste folosind driverele HAL este destul de mare (spatiu FLASH ocupat dublu). Desi folosind HAL consuma ceva mai putin RAM. Un program care face blink cu un delay non-blocant folosind un STM32F0xx: Folosind HAL: #include "stm32f0xx_hal.h" #define LD2_Pin GPIO_PIN_5 #define LD2_GPIO_Port GPIOA volatile uint32_t time_now = 0; void SystemClock_Config(void); static void MX_GPIO_Init(void); void hw_init(){ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /* Initialize all configured peripherals */ MX_GPIO_Init(); } int main(void){ hw_init(); time_now = HAL_GetTick(); while(1){ static uint8_t st = 0; if(!st && HAL_GetTick() >= (time_now + 500)){ st = 1; HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, st); time_now= HAL_GetTick(); } if(st && HAL_GetTick() >= (time_now + 50)){ st = 0; HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, st); time_now= HAL_GetTick(); } } } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; RCC_PeriphCLKInitTypeDef PeriphClkInit; /**Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48; RCC_OscInitStruct.HSI48State = RCC_HSI48_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; HAL_RCC_OscConfig(&RCC_OscInitStruct); /**Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI48; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1); PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2; PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1; HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit); /**Configure the Systick interrupt time */ HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); /**Configure the Systick */ HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); /* SysTick_IRQn interrupt configuration */ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); } /** Configure pins as * Analog * Input * Output * EVENT_OUT * EXTI */ static void MX_GPIO_Init(void){ GPIO_InitTypeDef GPIO_InitStruct; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOA_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET); /*Configure GPIO pin : LD2_Pin */ GPIO_InitStruct.Pin = LD2_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct); } text data bss dec 4022 52 268 4342 FLASH ocupat = 4022 + 52 = 4074 bytes RAM ocupat = 268 + 52 = 320 bytes ocupat Folosind SPL (Standard Peripheral Lib): #include <stdlib.h> #include "stm32f0xx.h" #include "cortexm/ExceptionHandlers.h" #define BLINK_ON_TICKS 250 #define BLINK_OFF_TICKS 100 volatile uint32_t counter_isr = 0; uint32_t time_now; void hw_config(){ // CLOCK CONFIG // start internal 48MHz oscillator RCC_HSI48Cmd(ENABLE); // wait for HSI48 to start while (RCC_GetFlagStatus(RCC_FLAG_HSI48RDY) == RESET); // set HSI48 as SYSCLK RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI48); // set HCLK as 48MHz RCC_HCLKConfig(RCC_SYSCLK_Div1); // set PCLK as 48MHz RCC_PCLKConfig(RCC_HCLK_Div1); // SYSTICK CONFIG SystemCoreClock = 48000000; SysTick_Config (SystemCoreClock / 1000); NVIC_SetPriority (SysTick_IRQn, 0); // PORT CONFIG // Enable GPIO Peripheral clock RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; // Configure pin in output push/pull mode GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_3; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure); } void SysTick_Handler(void){ counter_isr++; } uint32_t GetTick(){ volatile uint32_t time; time = counter_isr; return time; } int main(void){ uint8_t led_state = 0; hw_config(); time_now = GetTick(); while (1){ if (GetTick() >= (time_now + BLINK_ON_TICKS) && !led_state){ GPIO_WriteBit(GPIOA, GPIO_Pin_5, ENABLE); time_now = GetTick(); led_state = 1; } if (GetTick() >= (time_now + BLINK_OFF_TICKS) && led_state){ GPIO_WriteBit(GPIOA, GPIO_Pin_5, DISABLE); time_now= GetTick(); led_state = 0; } } } text data bss dec 1896 68 268 2232 FLASH ocupat = 1896 + 68 = 1964 bytes RAM ocupat = 268 + 68 = 336 bytes ocupat Editat Noiembrie 4, 2018 de mars01 Link spre comentariu
nico_2010 Postat Noiembrie 5, 2018 Autor Partajează Postat Noiembrie 5, 2018 (editat) @mars01 ai perfecta dreptate si recunosc ca de acest aspect m-am lovit si eu de curand cand am inceput sa lucrez la softul pentru o punte RCL (la care partea de hard este cam gata). Momentan, folosesc o placa de dezvoltare Nucleo F303RE si, cel putin in stadiul asta, deja am consumat circa 20k Flash si 2k RAM si nu vreau inca sa stiu care va fi finalul. Este foarte posibil asa fiu nevoit sa trec pe SPL sau, poate si mai convenabil, direct la programarea registrilor - acolo unde este cazul - pentru a ma incadra in posibilitatile unui STM32F100C6T6. Vom vedea. L.E.: Care a fost nivelul de optimizare in cele doua cazuri? Editat Noiembrie 5, 2018 de nico_2010 Link spre comentariu
Postări Recomandate
Creează un cont sau autentifică-te pentru a adăuga comentariu
Trebuie să fi un membru pentru a putea lăsa un comentariu.
Creează un cont
Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!
Înregistrează un nou contAutentificare
Ai deja un cont? Autentifică-te aici.
Autentifică-te acum