Stellaris Launchpad. 1. Превед, LED

Mar 31, 2013 17:25


Как нас учат классики, начинать программирование на новых языках или девайсах кошерно с хелловорда. Правда, по понятным причинам, выводить куда-то какой-то текст - не самая простая задача в наших условиях, поэтому мы будем не менее хрестоматийно моргать светодиодом, встроенным в плату.
Будем считать, что после прошлого раза у нас уже есть установленные StellarisWare и Code Composer Studio (CCS).
Скорее всего, с Keilом и IARом принципиально ничего не извенится, впрочем этот вопрос для себя я оставлю на "как нибудь потом".
Итак, запускаем CCS, первым делом идем в меню project->Import Existing CCS Eclipse project и импортируем все проекты, которые идут в составе Ware. Там много полезного и позновательного.
Теперь создаем новый проект, называем его как-нибудь и приступаем собственно к работе.
Вводная: Встроенный светодиод висит на порту F, пинах 1 (красный), 2 (синий) и 3 (зеленый).
У нас есть несколько путей реализовать задуманное.
1)Непосредситвенное управление регистрами, отвечающими за состояние портов, имеющих отношение к делу:

#include "inc/lm4f120h5qr.h"
#define LED_PIN 1

int main(void)
{
unsigned long i; //это счетчик цикла для задержки
SYSCTL_RCGCGPIO_R |= SYSCTL_RCGC2_GPIOF; //подключаем GPIO F к тактовому генератору
//тут нужна пауза минимум три такта, согласно даташиту
i = SYSCTL_RCGCGPIO_R; //это чтение не нужно, но оно даст необходимую задержку
GPIO_PORTF_DIR_R != 1 << LED_PIN; //объявляем нужный пин как выход
GPIO_PORTF_DEN_R != 1 << LED_PIN; //digital enable для нужного пина. По умолчанию, пин ничем находится в HI-Z состоянии

while(1)
{
GPIO_PORTF_DATA_R ^= 1 << LED_PIN; //переключаем состояние пина со светодиодом
for(i = 0; i < 1000000; i++){};//Пауза "сколько нибудь"
}
}

Все бы ничего, Но в мало-мальски срьезнос проекте от общения напрямую с регистрами крыша съедет моментально.
Кроме того, совсем непортабельно получается.
Вывод простой - нужен Abstraction Layer чтобы отделить зерна от плевел логику от аппаратной части.
В составе StellarisWare он уже есть, все лежит в библиотеке dirverlibs.
В этот раз получается как-то так (для разнооазия моргаем всеми тремя диодами):

#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_gpio.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"

#define RED_LED GPIO_PIN_1
#define BLUE_LED GPIO_PIN_2
#define GREEN_LED GPIO_PIN_3

int main(void)
{
unsigned int led_state = 0;
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); //включаем портF
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, RED_LED | BLUE_LED | GREEN_LED); //настраиваем пины RED_LED, BLUE_LED и GREEN_LED на выход
GPIOPinWrite(GPIO_PORTF_BASE, RED_LED|BLUE_LED|GREEN_LED, led_state); //гасим диод
while(1){ //loop forever
led_state ^= (RED_LED|GREEN_LED|BLUE_LED); //инвертируем состояние пина
GPIOPinWrite(GPIO_PORTF_BASE, RED_LED|BLUE_LED|GREEN_LED, led_state); //гасм или зажигаем диод
SysCtlDelay(1000000);
}
}

Но одними светодиодами сыт не будешь - данные неплозо не только выводить, но и принимать.
На плате есть две готовых пользовательских кнопки. Подключены они к пинам 4 и 0 порта F.
Схемотехнически, кнопки при нажатии замыкают соответствующий пн на землю.
То есть в теории все просто - на пине 1 - кнопка не нажата, на пине 0 - кнопка нажата.
Есть, правда, одна тонкость, которая в свое время стоила мне целого вечера разбирательств.
Одно из назначений пина на котором висит правая кнопка (PF0) - формировать Non-Maskable Interrupt (не спрашивайте меня, что это такое, ага?), соответственно все попытки любых манипуляций с этим пином процессор жестко пресекает, до тех пор, пока ему не сказать "ша, я знаю, что делаю."
Задачу сформулируем примерно так:
Красный диод мигает постоянно, нажатие лефой кнопки включает/выключает зеленый диод, нажатие правой - синий
Итак, код получается примерно такой:

#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_gpio.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"

#define SW1 GPIO_PIN_4
#define SW2 GPIO_PIN_0
#define RED_LED GPIO_PIN_1
#define BLUE_LED GPIO_PIN_2
#define GREEN_LED GPIO_PIN_3

int
main(void)
{
unsigned char red_state, green_state, blue_state, last_sw1, last_sw2;
unsigned int count;

SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); //включаем port F

HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY_DD; // волшебное колдунство
HWREG(GPIO_PORTF_BASE + GPIO_O_CR) = 0xFF; // для использования PF0
HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = 0; // Если вдруг кому надо - объясню подробнее

GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, RED_LED | BLUE_LED | GREEN_LED); //Пины светодиода на выход
GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, SW1 | SW2); //а кнопок - не вход
GPIOPadConfigSet(GPIO_PORTF_BASE, SW1 | SW2, GPIO_STRENGTH_2MA, //включаем кнопкам подтяжку вверх, чтобы в
GPIO_PIN_TYPE_STD_WPU); // ненажатом виде они выдавали 1

blue_state = green_state = 0;
count = 0;
red_state = RED_LED;
last_sw1 = last_sw2 = 1; //1 обозначает "не нажата"
GPIOPinWrite(GPIO_PORTF_BASE, RED_LED|BLUE_LED|GREEN_LED, red_state | blue_state | green_state);
while(1){ //loop forever
count++;
if(count >= LED_DELAY){ //раз в много циклов включаем/выключаем красный диод
count = 0;
red_state ^= RED_LED ;
GPIOPinWrite(GPIO_PORTF_BASE, RED_LED|BLUE_LED|GREEN_LED, red_state | blue_state | green_state);
}
if(!GPIOPinRead(GPIO_PORTF_BASE, SW1) && last_sw1) { //если только что нажата кнопка 1
green_state ^= GREEN_LED; //включаем/выключаем синий диод
last_sw1 = 0;
} else {
last_sw1 = GPIOPinRead(GPIO_PORTF_BASE, SW1);
}
if(!GPIOPinRead(GPIO_PORTF_BASE, SW2) && last_sw2) { //а если кнопка 2
blue_state ^= BLUE_LED; // зеленый
} else {
last_sw2 = GPIOPinRead(GPIO_PORTF_BASE, SW2);
}
}
}

На сегодня, наверное хватит. В следующий раз поработаем с таймерами.

stellaris launchpad, Микроконтроллеры

Previous post Next post
Up