- PVSM.RU - https://www.pvsm.ru -
В этом году компания Atmel анонсировала линейку «младших» кортексов М0+ семейства SAM D09, SAM D10, SAM D11. Эти не сильно «навороченные» контроллеры имеют низкую цену и небольшие корпуса. Причем в линейке присутствуют камни в легкопаяемых корпусах SOIC-14 и SOIC-20. Для ознакомления с возможностями контроллера доступны очень дешевые отладки из серии Xplained mini, которые совместимы с шилдами от Arduino. Эти особенности, возможно, вызовут интерес не только среди профессиональных разработчиков, но и у радиолюбителей.
Когда отладки попали к нам в руки, захотелось вместо «серьёзной» демонстрационной задачи в честь приближающегося Нового года сделать что-нибудь забавное и креативное. Мы поскребли по сусекам и нашли старенький проектик — тетрис на MEGA168 через терминалку и решили портировать его на новый камень и представить общественности. Практического смысла в этом никакого, что называется Just for fun. Кому интересны подробности, прошу под кат.
Внешний вид отладочной платы. Программатор на борту, подключение через разъем Micro USB.
Работа тетриса основана на нескольких базовых принципах:
Тетрис использует три команды [4] из протокола VT100 [5]: очистка экрана, перемещение курсора в начало и сделать курсор невидимым.
Для работы по этому протоколу можно использовать терминалку Tera term, например.
Для управления используются 5 клавиш-букв клавиатуры:
switch (c)
{
case 'w':
case ' ':
//ROTATE
tetris_rotate();
break;
case 's':
//DOWN
tetris_gravity();
break;
case 'd':
//RIGHT
tetris_move_right();
break;
case 'a':
//LEFT
tetris_move_left();
break;
default: break;
}
if (c == 'n')
{
c=0;
//Seed random function so we do not get same start condition
//for each new game. In essence we will not start a new game
//exactly at the same time.
srand(tick);
//New Game
is_running = true;
terminal_cursor_off();
terminal_clear();
tetris_init();
tetris_new_block();
terminal_cursor_home();
tetris_print();
}
Скорость игры устанавливается таймером. Для более опытных игроков можно задать «тиканье» быстрее, тогда и фигуры будут падать быстрее.
Конечно же, подсчитываются очки: за каждую исчезнувшую строку добавляется 100 очков. За каждую следующую «исчезнувшую» одновременно с первой, добавляется в два раза больше очков, чем за предыдущую.
Из периферии контролера нам нужен SERCOM в режиме UART для непосредственной передачи фигурок и картинки, и таймер для отсчета времени обновления картинки.
Вместо милой сердцу любого программиста 8-битных контроллеров настройки UART битами в регистрах:
static void board_init(void)
{
/*Configure IO pins:
* - UART pins
* - SW pin
* - LED pin
*/
DDRD &= ~USART_RX_PIN_bm;
DDRD |= USART_TX_PIN_bm;
PORTD |= USART_TX_PIN_bm;
PORTB |= SW_PIN_bm;
DDRB &= ~SW_PIN_bm;
/*Disable all modules we will not use*/
PRR = (1 << PRTWI) | (1 << PRTIM2) | (1 << PRTIM0) | (1 << PRSPI) | (1 << PRADC);
}
конфигурируем sercom для работы в режиме uart, не забывая разрешить прерывания и callback по приему символа.
static void configure_console(void)
{
struct usart_config usart_conf;
usart_get_config_defaults(&usart_conf);
usart_conf.mux_setting = CONF_STDIO_MUX_SETTING;
usart_conf.pinmux_pad0 = CONF_STDIO_PINMUX_PAD0;
usart_conf.pinmux_pad1 = CONF_STDIO_PINMUX_PAD1;
usart_conf.pinmux_pad2 = CONF_STDIO_PINMUX_PAD2;
usart_conf.pinmux_pad3 = CONF_STDIO_PINMUX_PAD3;
usart_conf.baudrate = CONF_STDIO_BAUDRATE;
stdio_serial_init(&cdc_uart_module, CONF_STDIO_USART_MODULE, &usart_conf);
}
enum status_code usart_enable_rx_interrupt( struct usart_module *const module, uint8_t *rx_data)
{
// Sanity check arguments
Assert(module);
Assert(rx_data);
// Issue internal asynchronous read
// Get a pointer to the hardware module instance
SercomUsart *const usart_hw = &(module->hw->USART);
module->rx_buffer_ptr = rx_data;
// Enable the RX Complete Interrupt
usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_RXC;
return STATUS_OK;
}
void configure_usart_callbacks(void)
{
usart_register_callback(&cdc_uart_module, USART_RX_callback, USART_CALLBACK_BUFFER_RECEIVED);
usart_enable_callback(&cdc_uart_module, USART_CALLBACK_BUFFER_RECEIVED);
}
В исходном коде для меги данные по uart принимались с помощью putc, для samd10 сделаем проще: пусть просто по прерыванию каждый полученный байт сваливается в определенную переменную. Это решение не претендует на правильность и безопасность, оно для простоты перехода и ускорения его.
Подробно про то, как победить порой слишком «умную» ASF для приема одного байта по прерываниям, мы писали в нашей статье [6] на сайте we.easyelectronics.ru.
Перейдем к таймерам.
Код для меги:
void init_timer(void)
{
/*Start timer used to iterate game and seed random function*/
TIFR1 = 1 << OCF1A;
TIMSK1 = 1 << OCIE1A;
OCR1A = TIMER_TOP_VALUE;
TCCR1B = (1 << WGM12) | (1 << CS12) | (1 << CS10);
}
ISR(TIMER1_COMPA_vect, ISR_BLOCK)
{
++tick;
iterate_game = true;
}
И соответствующий код для samd10
/** Configures TC function with the driver.
*/
static void configure_tc(void)
{
struct tc_config config_tc;
tc_get_config_defaults(&config_tc);
config_tc.counter_size = TC_COUNTER_SIZE_16BIT;
config_tc.wave_generation = TC_WAVE_GENERATION_MATCH_FREQ;
config_tc.counter_16_bit.compare_capture_channel[0] = 2000;
config_tc.clock_prescaler=TC_CLOCK_PRESCALER_DIV1024;
tc_init(&tc_instance, CONF_TC_INSTANCE, &config_tc);
tc_enable(&tc_instance);
}
/** Registers TC callback function with the driver.
*/
static void configure_tc_callbacks(void)
{
tc_register_callback(&tc_instance, tc_callback_to_counter, TC_CALLBACK_CC_CHANNEL0);
tc_enable_callback(&tc_instance, TC_CALLBACK_CC_CHANNEL0);
}
static void tc_callback_to_counter( struct tc_module *const module_inst)
{
++tick;
iterate_game = true;
}
Вот и все. Весь остальной код для обработки движения фигур и всей остальной логики остается таким же.
Полностью проект для samd 10 лежит на github [7].
Стоимость отладочной платы ATSAMD10-XMINI [8] составляет 450 рублей.
Автор: Rainbow
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/arduino/106647
Ссылки в тексте:
[1] SAM D09: http://www.atmel.com/products/microcontrollers/arm/sam-d.aspx#samd09
[2] SAM D10: http://www.atmel.com/products/microcontrollers/arm/sam-d.aspx#samd10
[3] SAM D11: http://www.atmel.com/products/microcontrollers/arm/sam-d.aspx#samd11
[4] команды: https://ttssh2.osdn.jp/manual/en/about/ctrlseq.html#CSI
[5] VT100: https://ru.wikipedia.org/wiki/VT100
[6] статье: http://we.easyelectronics.ru/cortex/nastroyka-uart-po-preryvaniyam-dlya-atmel-sam-d20-d21.html
[7] github: https://github.com/marus-ka/tetris_samd10
[8] ATSAMD10-XMINI: http://r-ng.ru/node/67
[9] Источник: http://geektimes.ru/post/267840/
Нажмите здесь для печати.