Tetris auf einem Mikrocontroller in Tera Term

    In diesem Jahr kündigte Atmel eine Reihe von „Junior“ -M0 + -Kortexen der SAM D09, SAM D10, SAM D11-Familie an. Dies sind keine sehr "hoch entwickelten" Steuerungen, die einen niedrigen Preis und kleine Gehäuse haben. Darüber hinaus gibt es in der Reihe Steine ​​in einfach zu verlötenden SOIC-14- und SOIC-20-Gehäusen. Um sich mit den Fähigkeiten des Controllers vertraut zu machen, stehen sehr günstige Debugs aus der Xplained Mini-Serie zur Verfügung, die mit Shields von Arduino kompatibel sind. Diese Funktionen sind möglicherweise nicht nur für professionelle Entwickler von Interesse, sondern auch für Amateurfunkbegeisterte.

    Als das Debuggen in unsere Hände fiel, wollte ich zu Ehren des bevorstehenden neuen Jahres etwas Lustiges und Kreatives anstelle der „ernsthaften“ Demonstrationsaufgabe tun. Wir haben die Eingeweide durchwühlt und eine alte Projektion gefunden - Tetris auf MEGA168 durch das Terminal und beschlossen, sie auf einen neuen Stein zu portieren und der Öffentlichkeit vorzustellen. Es gibt keinen praktischen Sinn, der nur zum Spaß genannt wird. Wer sich für die Details interessiert, bitte unter der Katze.



    Kurz über die neuen Mikrocontroller


    • SAM D09 ist das jüngste Mitglied der SAM D-Familie und verfügt über einen 8K- oder 16K-Flash und einen 4K-SRAM. Gehäuseoptionen QFN-24 und SOIC-14. Onboard DMA und Event System. 2 SERCOM - Universelle Kommunikationsmodule, die als USART, SPI oder I2C konfiguriert werden können. 5 oder 10 Kanal 12 Bit ADC.
    • SAM D10 ist ein Upgrade von D09, das zusätzliche Timer, einen Analogkomparator, einen DAC und einen Touch-Button-Controller sowie ein zusätzliches SERCOM für einige Modifikationen enthält. Gehäuseoptionen QFN-24, SOIC-14, SOIC-20.
    • SAM D11 ist der gleiche D10, jedoch mit einem zusätzlichen Full-Speed-USB-Gerät.


    Das Aussehen der Debug-Karte. On-Board-Programmierer, Anschluss über Micro-USB-Anschluss.

    Nun zu Tetris selbst


    Die Arbeit von Tetris basiert auf mehreren Grundprinzipien:
    • Die Kommunikation mit dem Terminal erfolgt nach dem VT100-Protokoll.
    • das Bild wird per Timer aktualisiert,
    • Jede Figur passt in ein Quadrat bestimmter Größe (4 mal 4 Zeichen).

    Tetris verwendet drei Befehle aus dem VT100- Protokoll : Löschen Sie den Bildschirm, bewegen Sie den Cursor an den Anfang und machen Sie den Cursor unsichtbar.
    Um an diesem Protokoll zu arbeiten, können Sie beispielsweise das Tera Term Terminal verwenden.
    Zur Steuerung werden 5 Tastaturbuchstaben verwendet:
    • n - Starte ein neues Spiel,
    • w oder space - eine Form drehen,
    • s - die Figur fallen lassen,
    • d - nach rechts bewegen,
    • a - nach links bewegen.

    Im Code können Sie die Steuertasten einfach anderen zuweisen
    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();
    }	
    



    Die Spielgeschwindigkeit wird durch einen Timer eingestellt. Für erfahrene Spieler können Sie das Häkchen schneller setzen, dann fallen die Steine ​​schneller.

    Natürlich werden Punkte gezählt: Für jede verschwundene Linie werden 100 Punkte addiert. Für jedes nachfolgende "Verschwindenlassen" gleichzeitig mit dem ersten werden zwei Mal mehr Punkte addiert als für das vorherige.

    Portierung von Mega nach Samd10


    Von der Peripherie des Controllers benötigen wir SERCOM im UART-Modus für die direkte Übertragung von Zahlen und Bildern sowie einen Timer zum Zählen der Zeit, in der das Bild aktualisiert wird.

    Anstelle der 8-Bit-Controller eines Programmierers, die jedem Programmierer am Herzen liegen, setzen Sie UART-Bits in Registern:
    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);
    }
    

    Wir konfigurieren sercom so, dass es im Uart-Modus arbeitet, ohne zu vergessen, dass Interrupts und Rückrufe für den Empfang eines Zeichens zugelassen werden.
    Sercom-Konfiguration im Uart-Modus
    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);
    }
    



    Im Quellcode für Mega wurden Daten über UART mit putc empfangen, für samd10 vereinfachen wir dies: Lassen Sie einfach jedes empfangene Byte durch einen Interrupt in eine bestimmte Variable fallen. Diese Lösung erhebt keinen Anspruch auf Richtigkeit und Sicherheit, sondern erleichtert den Übergang und beschleunigt ihn.
    In unserem Artikel über we.easyelectronics.ru haben wir ausführlich beschrieben, wie man manchmal zu "intelligente" ASFs besiegt , um ein Byte per Interrupt zu empfangen.

    Kommen wir zu den Timern.
    Code für Mega:
    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;
    }
    


    Und der entsprechende Code für 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;
    }
    


    Das ist alles. Der Rest des Codes zur Handhabung der Bewegung der Figuren und der Rest der Logik bleibt gleich.
    Das komplette Projekt für samd 10 liegt auf Github .

    Einstellungen für Tera Term:






    Die Kosten für das Debug Board ATSAMD10-XMINI betragen 450 Rubel.

    Jetzt auch beliebt: