Для обработчика системного исключения таймера SysTick заголовок функции-обработчика будет выглядеть так:
Для обеспечения корректной работы обработчика необходимо , как минимум, назначить системному исключению приоритет и сбросить его в неактивное состояние после обработки (т.е., всё так же, как и у обычного прерывания). Но приоритеты системных исключений назначаются не в регистрах NVIC, а в регистрах системного блока управления (System control block), которые называются SHPR1 — SHPR3 (для разнообразия, они нумеруются, начиная с 1, а не с 0, т.е. регистра SHPR0 не существует). Приоритет системного исключения SysTick задаётся в регистре SHPR3, в битах [31:24]. Адрес регистра SHPR3 равен 0xE000ED20, и мы можем записать:
Сброс прерывания SysTick в неактивное состояние осуществляется с помощью регистра ICSR того же системного блока управления.
Обработчик системного исключения SysTick выглядит так:
И, в заключение, ещё одна особенность, на этот раз связанная с обработкой прерывания Repetitive Interrupt Handler. У этого прерывания сброс в неактивное состояние нужно выполнять так:
Здесь RICTRL — регистр управления самого таймера RIT. Сброс прерывания в контроллере NVIC выполнится при этом автоматически.
В Cortex-M перечень (имен)функций обработчиков прерывания можно найти в startup.S. Эти функции имеют атрибут weak - "слабый", и вместо тел функций обработчиков проложены заглушки. Для задействования своего обработчика достаточно написать в любом *.c файле, включенном в проект, своей функции с тем же именем - компилятор зацепит её - она без атрибута weak. В Cortex-M завсегда есть в ядре SysTick таймер. Для его использования нужно выполнить SysTick_Config() и написать свой обработчик SysTick_Handler.
unsigned long SysTickCounter;
void SysTick_Handler(void){
SysTickCounter++;
// здесь, например, вставляем свои таймерные прибамбахи типо индикации
}
unsigned long clock(void){
return SysTickCounter;
}
unsigned long clock_Elapsed(unsigned long start){
return clock() - start; //вычитание беззнаковых - если clock() < start, результат в эквиваленте даст clock() + ~0UL -
start, т.е. start - clock()
}
int main(void){
SystemCoreClockUpdate();//в STM32 при работе от кварца значение SystemCoreClock пересчитывается из константы HSE_Value
SysTick_Config(SystemCoreClock/1000);//1 ms; для 100 мкс SystemCoreClock/10000, для 10 мс - SystemCoreClock/100
...
unsigned long ts;
do{
ts = clock();
LED_toggle();//тут придётся потрудиться:) написать мигалку
while(clock_Elapsed(ts) < 100){//delay 100 ms
;//здесь тоже можно заняться чем-то полезным
}
}while(1);
}
void SysTick_Handler(void)
Для обеспечения корректной работы обработчика необходимо , как минимум, назначить системному исключению приоритет и сбросить его в неактивное состояние после обработки (т.е., всё так же, как и у обычного прерывания). Но приоритеты системных исключений назначаются не в регистрах NVIC, а в регистрах системного блока управления (System control block), которые называются SHPR1 — SHPR3 (для разнообразия, они нумеруются, начиная с 1, а не с 0, т.е. регистра SHPR0 не существует). Приоритет системного исключения SysTick задаётся в регистре SHPR3, в битах [31:24]. Адрес регистра SHPR3 равен 0xE000ED20, и мы можем записать:
unsigned long * pSHPR3 = (unsigned long *)0xE000ED20; * pSHPR3 = SYS_TICK_PRIORITY << 24;
|
Обработчик системного исключения SysTick выглядит так:
void SysTick_Handler(void) { //тело обработчика //сброс прерывания ICSR_bit.PENDSTCLR = 1; }
И, в заключение, ещё одна особенность, на этот раз связанная с обработкой прерывания Repetitive Interrupt Handler. У этого прерывания сброс в неактивное состояние нужно выполнять так:
RICTRL_bit.RITINT = 1;
|
В Cortex-M перечень (имен)функций обработчиков прерывания можно найти в startup.S. Эти функции имеют атрибут weak - "слабый", и вместо тел функций обработчиков проложены заглушки. Для задействования своего обработчика достаточно написать в любом *.c файле, включенном в проект, своей функции с тем же именем - компилятор зацепит её - она без атрибута weak. В Cortex-M завсегда есть в ядре SysTick таймер. Для его использования нужно выполнить SysTick_Config() и написать свой обработчик SysTick_Handler.
unsigned long SysTickCounter;
void SysTick_Handler(void){
SysTickCounter++;
// здесь, например, вставляем свои таймерные прибамбахи типо индикации
}
unsigned long clock(void){
return SysTickCounter;
}
unsigned long clock_Elapsed(unsigned long start){
return clock() - start; //вычитание беззнаковых - если clock() < start, результат в эквиваленте даст clock() + ~0UL -
start, т.е. start - clock()
}
int main(void){
SystemCoreClockUpdate();//в STM32 при работе от кварца значение SystemCoreClock пересчитывается из константы HSE_Value
SysTick_Config(SystemCoreClock/1000);//1 ms; для 100 мкс SystemCoreClock/10000, для 10 мс - SystemCoreClock/100
...
unsigned long ts;
do{
ts = clock();
LED_toggle();//тут придётся потрудиться:) написать мигалку
while(clock_Elapsed(ts) < 100){//delay 100 ms
;//здесь тоже можно заняться чем-то полезным
}
}while(1);
}
а как получить задержку в 1 микросекунду?
ОтветитьУдалить