Внешние прерывания в микроконтроллерах серии "L", на примере: stm8l151 и IAR WORKWENCH

разделы: STM8 , дата: 9 июля 2016г.

В микроконтроллере stm8l151, внешние прерывания организованы несколько иначе чем, в S-серии. Если посмотреть на таблицу прерываний слева, то наряду с прерываниями для портов E/F, B/G и D/I, имеются также прерывания для пинов 0-7. Эти прерывания являются общими для всех портов, вследствии чего, для их использования можно назначить любой порт. Они не привяны жестко к какому-то конкретному пину, как в AVR. При этом, такие прерывания могут обрабатывать сигналы с нескольких портов, если на них установить соотвествующий флаг в Px_CR2.

Наряду с конфигурирующими регистрами EXTI_CRx из S-серии, здесь имеются еще регистры EXTI_SRx и EXTI_CONF:

Первый, это флаговый регистр, а через второй можно выбрать, использовать ли прерывание по порту или прерывания по номеру пину. Тут или-или, и то и другое использовать не получится.

Кроме того, в EXTI_CONF, порты разделены пополам, т.е. младшую или старшую половину порта можно отдать на прерывание по порту, а остальное на прерывания о пину.

EXTI_SR - это флаговые регистры, которые по идее должны помочь распарсить прерывание, когда на нем несколько пинов висит. Первый работает с прерываниями по пину и указывает на пин, второй работает с прерываниями по порту. Но вот идея их принудительной очистки записью единицы(так написно в официальной документации), как-то не кажется здравой.

В остальном, работа с прерываниями не отличается работы с прерываниями от S-серии.

По мотивам этой статьи, я составил вариант финальной программы из предыдущего поста, переписанный под IAR и 151-й чип:

#include "iostm8l151c8.h"      

static void delay(unsigned int t)
{
	while(t--);
}

#pragma vector=EXTI3_vector
__interrupt void press_button(void){
	if (PA_IDR_bit.IDR3 == 1)
   		 PA_ODR_bit.ODR4=1;
   	else
    		PA_ODR_bit.ODR4=0;

  	EXTI_SR1_bit.P3F=1;   //escape from interrupt
}

int main( void )         // Основная программа
{
	//  PA2 - led SIGNAL
  	PA_DDR_bit.DDR2=1;
  	PA_CR1_bit.C12=1;
  	//  PA4 - led WORK indication
  	PA_DDR_bit.DDR4=1;
  	PA_CR1_bit.C14=1;

  	// PA3 - button
  	PA_DDR_bit.DDR3=0;
  	PA_CR1_bit.C13=0;
 	PA_CR2_bit.C23=1;  // enable interrupt
  	EXTI_CR1_bit.P3IS=3; //any change

  	CLK_CKDIVR=4; // 1MHz
  	CPU_CFG_GCR_bit.AL = 1;

  	asm("RIM");
  	asm("HALT");
  	for(;;) {
    		delay(30000);
    		PA_ODR ^= MASK_PA_ODR_ODR2;
  	}

}

Здесь на PA3 подключена кнопка, на PA2 светодиод, который загорается когда нажата кнопка, а светодиод на PA4 мигает из главного цикла основной программы. Если он не светится, значит микроконтроллер в спящем режиме.

Кстати, потребление микроконтроллера в спяшем режиме от 3.3 вольтовой батареи типа "таблетка" 43 мкА. Это на порядок больше, у MSP430 в аналогичном режиме, но тоже не плохо.

Попытался запитать микроконтроллер от двух Ni-NH аккамуляторов типа "AAA", в сумме они дали 2.9 Вольт, и потребление упало до 9мкА. Перепроверял десять раз, факт есть факт. Аккамуляторы были заряжены до упора, "проседать" не должны. Видимо от типа аккамулятора тоже зависит энергопотребленние.

Для stm8l051 код будет идентичен вышеприведенному, разве что порты другие. И еще такой ньюанс. Потребление для моего 051-го чипа в halt режиме вышло на уровне аж 170-200 мкА. Возможно не стоило было брать чип на Али? 151-й я брал в обычном магазине...

код:


#include "iostm8l051f3.h"      // подключение заголовочного файла с объявлениями регистров, масок и битов

static void delay(unsigned int t)
{
	while(t--);
}

#pragma vector=EXTI3_vector
__interrupt void press_button(void){
	if (PB_IDR_bit.IDR3 == 1)
    		PB_ODR_bit.ODR1=1;
   	else
    		PB_ODR_bit.ODR1=0;

  	EXTI_SR1_bit.P3F=1;   //escape from interrupt
}

int main( void )         // Основная программа
{
  	//  PB1 - led WORK indication
	PB_DDR_bit.DDR1=1;
	PB_CR1_bit.C11=1;
  	//  PB2 - led SIGNAL
  	PB_DDR_bit.DDR2=1;
  	PB_CR1_bit.C12=1;

  	// PB3 - button
  	PB_DDR_bit.DDR3=0;
  	PB_CR1_bit.C13=0;
  	PB_CR2_bit.C23=1;  // enable interrupt
  	EXTI_CR1_bit.P3IS=3; //any change

  	CLK_CKDIVR=4; // 1MHz
  	CPU_CFG_GCR_bit.AL = 1;

  	asm("RIM");
  	asm("HALT");
  	for(;;) {
    		delay(60000);
    		PB_ODR ^= MASK_PB_ODR_ODR2;

  	}

}

здесь на PB1 подключается светодиод - индикатор нажатой кнопки, на PB2 - светодиод - индикатор рабочего цикла, на PB3 сама кнопка.

поделиться: