در قسمت هفدهم آموزش میکروکنترلر STM8 تایمر۲ را بهشما معرفیکردیم. در این قسمت از مجموعه مقالات آموزش میکروکنترلر STM8 قصد داریم تایمر۴ را آموزشدهیم. با ما همراه باشید.
تایمر۴
در میکروکنترلر، تایمر۴ نسبتبه دیگر تایمرها از اهمیت بالاتری برخوردار است. در این مقاله، نحوه اسکن و نمایشاطلاعات روی سونسگمنت بااستفادهاز وقفه را نشان میدهیم، درحالیکه حلقهی اصلی میتواند اطلاعات را نمایشدهد.
اتصالات سختافزاری
نمونهکد تایمر۴
main.c
#include "STM8S.h" unsigned int value = 0x00; unsigned char n = 0x00; const unsigned char num[0x0A] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; void GPIO_setup(void); void clock_setup(void); void TIM4_setup(void); void main(void) { int j=0; GPIO_setup(); clock_setup(); TIM4_setup(); while(TRUE) { value++; for(j=0;j<0x3FFF;j++); }; } void GPIO_setup(void) { GPIO_DeInit(GPIOC); GPIO_DeInit(GPIOD); GPIO_DeInit(GPIOB); GPIO_Init(GPIOD, ((GPIO_Pin_TypeDef)(GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5)), GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(GPIOD, GPIO_PIN_1| GPIO_PIN_6, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(GPIOC, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 , GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(GPIOB, GPIO_PIN_4 | GPIO_PIN_5, GPIO_MODE_OUT_PP_LOW_FAST); } void clock_setup(void) { CLK_DeInit(); CLK_HSECmd(DISABLE); CLK_LSICmd(DISABLE); CLK_HSICmd(ENABLE); while(CLK_GetFlagStatus(CLK_FLAG_HSIRDY) == FALSE); CLK_ClockSwitchCmd(ENABLE); CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV8); CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1); CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI, DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_AWU, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_UART1, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER1, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER2, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER4, ENABLE); } void TIM4_setup(void) { TIM4_DeInit(); TIM4_TimeBaseInit(TIM4_PRESCALER_32, 128); TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE); TIM4_Cmd(ENABLE); enableInterrupts(); }
(stm8s_it.h (top part only
#ifndef __STM8S_IT_H #define __STM8S_IT_H @far @interrupt void TIM4_UPD_IRQHandler(void); /* Includes ------------------------------------------------------------------*/ #include "stm8s.h"
stm8s_it.c
#include "stm8s.h" #include "stm8s_it.h" extern unsigned int value; extern unsigned char n; extern unsigned char seg; extern const unsigned char num[10]; #define SEG_A 1 #define SEG_B 2 #define SEG_C 4 #define SEG_D 8 #define SEG_E 16 #define SEG_F 32 #define SEG_G 64 #define SegNum_0 (SEG_A|SEG_B|SEG_C|SEG_D|SEG_E|SEG_F) #define SegNum_1 (SEG_B|SEG_C) #define SegNum_2 (SEG_A|SEG_B|SEG_D|SEG_E|SEG_G) #define SegNum_3 (SEG_A|SEG_B|SEG_C|SEG_D|SEG_G) #define SegNum_4 (SEG_B|SEG_C|SEG_F|SEG_G) #define SegNum_5 (SEG_A|SEG_C|SEG_D|SEG_F|SEG_G) #define SegNum_6 (SEG_A|SEG_C|SEG_D|SEG_E|SEG_F|SEG_G) #define SegNum_7 (SEG_A|SEG_B|SEG_C) #define SegNum_8 (SEG_A|SEG_B|SEG_C|SEG_D|SEG_E|SEG_F|SEG_G) #define SegNum_9 (SEG_A|SEG_B|SEG_C|SEG_D|SEG_F|SEG_G) void SegWriteByte(char Data) { int i; char Pin[] = {GPIO_PIN_1,GPIO_PIN_7,GPIO_PIN_6,GPIO_PIN_5,GPIO_PIN_4,GPIO_PIN_3,GPIO_PIN_6}; GPIO_TypeDef *GPIOx[]= {GPIOD, GPIOC, GPIOC, GPIOC, GPIOC, GPIOC, GPIOD}; for( i=0;i<7;i++) { if(Data&1) { GPIOx[i]->ODR |=Pin[i]; } else { GPIOx[i]->ODR &=~Pin[i]; } Data>>=1; } GPIO_WriteHigh(GPIOB, GPIO_PIN_4); } void TIM4_UPD_IRQHandler(void) { static char index = 0; GPIOD->ODR &=~((GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5)); switch(index++) { case 0: n = (value / 1000); SegWriteByte(num[n]); GPIOD->ODR |=(GPIO_PIN_5); break; case 1: n = ((value / 100) % 10); SegWriteByte(num[n]); GPIOD->ODR |=(GPIO_PIN_4); break; case 2: n = ((value / 10) % 10); SegWriteByte(num[n]); GPIOD->ODR |=(GPIO_PIN_3); break; case 3: n = (value % 10); SegWriteByte(num[n]); GPIOD->ODR |=(GPIO_PIN_2); break; } if(index>3) index = 0; TIM4_ClearFlag(TIM4_FLAG_UPDATE); }
stm8_interrupt_vector.c
/* BASIC INTERRUPT VECTOR TABLE FOR STM8 devices * Copyright (c) 2007 STMicroelectronics */ #include "stm8s_it.h" typedef void @far (*interrupt_handler_t)(void); struct interrupt_vector { unsigned char interrupt_instruction; interrupt_handler_t interrupt_handler; }; @far @interrupt void NonHandledInterrupt (void) { /* in order to detect unexpected events during development, it is recommended to set a breakpoint on the following instruction */ return; } extern void _stext(); /* startup routine */ //@far @interrupt void TIM4_UPD_IRQHandler(void) ; struct interrupt_vector const _vectab[] = { {0x82, (interrupt_handler_t)_stext}, /* reset */ {0x82, NonHandledInterrupt}, /* trap */ {0x82, NonHandledInterrupt}, /* irq0 */ {0x82, NonHandledInterrupt}, /* irq1 */ {0x82, NonHandledInterrupt}, /* irq2 */ {0x82, NonHandledInterrupt}, /* irq3 */ {0x82, NonHandledInterrupt}, /* irq4 */ {0x82, NonHandledInterrupt}, /* irq5 */ {0x82, NonHandledInterrupt}, /* irq6 */ {0x82, NonHandledInterrupt}, /* irq7 */ {0x82, NonHandledInterrupt}, /* irq8 */ {0x82, NonHandledInterrupt}, /* irq9 */ {0x82, NonHandledInterrupt}, /* irq10 */ {0x82, NonHandledInterrupt}, /* irq11 */ {0x82, NonHandledInterrupt}, /* irq12 */ {0x82, NonHandledInterrupt}, /* irq13 */ {0x82, NonHandledInterrupt}, /* irq14 */ {0x82, NonHandledInterrupt}, /* irq15 */ {0x82, NonHandledInterrupt}, /* irq16 */ {0x82, NonHandledInterrupt}, /* irq17 */ {0x82, NonHandledInterrupt}, /* irq18 */ {0x82, NonHandledInterrupt}, /* irq19 */ {0x82, NonHandledInterrupt}, /* irq20 */ {0x82, NonHandledInterrupt}, /* irq21 */ {0x82, NonHandledInterrupt}, /* irq22 */ {0x82, (interrupt_handler_t)TIM4_UPD_IRQHandler}, /* irq23 */ {0x82, NonHandledInterrupt}, /* irq24 */ {0x82, NonHandledInterrupt}, /* irq25 */ {0x82, NonHandledInterrupt}, /* irq26 */ {0x82, NonHandledInterrupt}, /* irq27 */ {0x82, NonHandledInterrupt}, /* irq28 */ {0x82, NonHandledInterrupt}, /* irq29 */ };
توضیحات
کلاک داخلی و CPU هردو روی ۲مگاهرتز کار میکنند.
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV8); CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1); .... …. CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER4, ENABLE);
تایمر۴ یک تایمر پایه است و بهتر است آنرا برای کارهای ساده استفادهکنیم. ما آنرا با مقدار پیشفرض ۳۲ و بارگیری شمارنده روی ۱۲۸ تنظیمکردیم. این مقادیر باعث میشود تایمر۴ سرریز کند و وقفهای ۲msای ایجادکند. که این مدتزمان برای نمایش اطلاعات برروی یک سون سگمنت کافیاست. در اینجا ۴ عدد سون سگمنت درطول ۸ms بهروز میشوند ولی چشم شما تمامی اطلاعات را در یک لحظه می بیند، درواقع در اینجا به مغز انسان حقه میزنیم. درنهایت، باید وقفههای که موردنیاز هستند را فعالکنیم.
void TIM4_setup(void) { TIM4_DeInit(); TIM4_TimeBaseInit(TIM4_PRESCALER_32, 128); TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE); TIM4_Cmd(ENABLE); enableInterrupts(); }
اولین مثال از وقفهها در مجموعه آموزش میکروکنترلر STM8 را بهیاد میآورید؟ همانطورکه در پستهای قبل دیدیم ما باید به کامپایلر بگوییم که از کدام وقفه استفاده میکنیم. باتوجهبه دیتاشیت مشاهده میشود که آپدیت و سرریز تایمر۴ در IRQ4 قرار دارد. بنابراین باید این تغییرات را در فایل stm8_interrupt_vector.c انجام دهیم:
{0x82, (interrupt_handler_t)TIM4_UPD_IRQHandler}, /* irq23 */
بهیاد داشتهباشید که چون در این کد از وقفه استفاده میکنیم فایلهای هدر و سورسوقفه را اضافهکنید. درون ISR، اسکن هر سون سگمنت را انجام میدهیم. هربار که وقفه سرریز کند سون سگمنت تغییر میکند. در پایان ISR یک شماره افزایش مییابد تا درهنگام سرریز جدید صفحه نمایش بعدی را انتخابکند. در داخل Switch-Case، سون سگمنتها را فعال و درباره مقداری را که باید نشاندهند تصمیم میگیریم. سرانجام پرچم سرریز/بهروزرسانی پاک میشود.
در قسمت نوزدهم از مجموعه آموزش میکروکنترلر STM8 تایمر۲ (PWM) را موردبررسی قرار میدهیم. با ما همراه باشید.
منبع:سیسوگ