Schaeffler Modul 3A: Rozdiel medzi revíziami
Zo stránky SensorWiki
Bez shrnutí editace |
|||
(7 medziľahlých úprav od rovnakého používateľa nie je zobrazených.) | |||
Riadok 28: | Riadok 28: | ||
=== 1. Bare-metal prístup k programovaniu === | === 1. Bare-metal prístup k programovaniu === | ||
Bare metal znamená, že budeme priamo programovať procesor bez využívania akýchkoľvek knižníc, takmer na strojovej úrovni. Vyžaduje si to do hĺbky preštudovať manuál k danému procesoru. Preto túto časť budeme chápať len ako ukážku, nebudeme to skutočne programovať. | |||
Ak chceme v programe použiť funkciu '''printf''' na vysielanie znakov, musíme si ju doprogramovať. Jeden prístup predstavuje kompilátor avr-gcc pre procesory AVR. Stačí mať vlastnú implementáciu funkcií putc() a getc() a printf bude fungovať na ľubovoľnom vstupno-výstupnom zariadení. | |||
<tabs> | |||
<tab name="demo.c"><source lang="c++" style="background: LightYellow;"> | |||
#define BAUD 9600 | |||
#include <avr/io.h> | |||
#include "uart.h" | |||
#include <stdio.h> | |||
... | |||
FILE mystdout = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE); | |||
int main(void) | |||
{ | |||
uart_init(); // Inicializacia seriovej linky | |||
stdout = &mystdout; // Odteraz funguje printf(); | |||
printf("Hello, world!"); | |||
return 0; | |||
} | |||
</source></tab> | |||
<tab name="uart.h"><source lang="c++" style="background: LightYellow;"> | |||
/* ************************************************************************* */ | |||
/* FileName : uart.h */ | |||
/* ************************************************************************* */ | |||
void uart_init( void ); | |||
void uart_putc( char c ); | |||
char uart_getc( void ); | |||
</source></tab> | |||
<tab name="uart.c"><source lang="c++" style="background: LightYellow;"> | |||
#include <avr/io.h> | |||
#include <util/setbaud.h> | |||
void uart_init( void ) | |||
{ | |||
UBRR0H = UBRRH_VALUE; | |||
UBRR0L = UBRRL_VALUE; | |||
#if USE_2X | |||
UCSR0A |= _BV(U2X0); | |||
#else | |||
UCSR0A &= ~(_BV(U2X0)); | |||
#endif | |||
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */ | |||
UCSR0B = _BV(RXEN0) | _BV(TXEN0); /* Enable RX and TX */ | |||
} | |||
void uart_putc(char c) | |||
{ | |||
if (c == '\n') | |||
{ | |||
uart_putc('\r'); | |||
} | |||
loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */ | |||
UDR0 = c; | |||
} | |||
char uart_getc(void) { | |||
loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */ | |||
return UDR0; | |||
} | |||
</source></tab> | |||
</tabs> | |||
Iný prístup je v jazyku C pre procesory ARM, kde je implementácia funkcie printf rozdelená na dve časti: jedna časť je nezávislá od výstupného zariadenia a postará sa o vstupné dáta vrátane ich formátovania, takže máme k dispozícii hotovú postupnosť znakov. Druhá časť, ktorá zabezpečí samotné odostlanie znakov je samozrejme závislá na hardvéri. Akýkoľvek program, ktorý chce funkciu printf využívať, musí zabezpečiť vlastnú implementáciu funkcie print_buf definovanej nasledovne | |||
void print_buf(const char *buf, int n) | |||
Jej vstupom je reťazec (postupnosť) znakov a počet znakov, takže v princípe stačí v jednoduchej slučke poslať znaky na prslušné výstupné zariadenie, v našom prípade na obvod UART. V zložitejšícch aplikáciach na to využijeme služby nejakého operačného systému. | |||
<tabs> | <tabs> | ||
<tab name="main.c"><source lang="python" style="background: LightBlue;"> | <tab name="main.c"><source lang="python" style="background: LightBlue;"> | ||
#include "microbian.h" | |||
#include "hardware.h" | #include "hardware.h" | ||
#include "serial.h" | #include "serial.h" | ||
#include "lib.h" | |||
#include "accel.h" | |||
void | |||
static void main(int n) | |||
{ | { | ||
int x, y, z; | |||
timer_delay(1000); | |||
accel_start(); | |||
while (1) | |||
{ | |||
timer_delay(200); | |||
accel_reading(&x, &y, &z); | |||
printf("%d,%d,%d\n", x, y, z); | |||
} | } | ||
} | } | ||
void init(void) | |||
{ | |||
serial_init(); | |||
timer_init(); | |||
i2c_init(I2C_INTERNAL); | |||
start("Main", main, 0, STACK); | |||
} | |||
</source></tab> | </source></tab> | ||
Riadok 97: | Riadok 202: | ||
</source></tab> | </source></tab> | ||
<tab name="hardware.h"><source lang="c++" style="background: LightGreen;"> | <tab name="hardware.h"><source lang="c++" style="background: LightGreen;"> | ||
/* Časť súboru hardware.h s definíciami týkajúcimi sa UART rozhrania */ | |||
/* UART */ | |||
/* Interrupts */ | |||
#define UART_INT_RXDRDY 2 | |||
#define UART_INT_TXDRDY 7 | |||
#define UART_BASE _BASE(0x40002000) | |||
/* Tasks */ | |||
#define UART_STARTRX _REG(unsigned, 0x40002000) | |||
#define UART_STARTTX _REG(unsigned, 0x40002008) | |||
/* Events */ | |||
#define UART_RXDRDY _REG(unsigned, 0x40002108) | |||
#define UART_TXDRDY _REG(unsigned, 0x4000211c) | |||
/* Registers */ | |||
#define UART_INTENSET _REG(unsigned, 0x40002304) | |||
#define UART_INTENCLR _REG(unsigned, 0x40002308) | |||
#define UART_ENABLE _REG(unsigned, 0x40002500) | |||
#define UART_ENABLE_Disabled 0 | |||
#define UART_ENABLE_Enabled 4 | |||
#define UART_PSELTXD _REG(unsigned, 0x4000250c) | |||
#define UART_PSELRXD _REG(unsigned, 0x40002514) | |||
#define UART_RXD _REG(unsigned, 0x40002518) | |||
#define UART_TXD _REG(unsigned, 0x4000251c) | |||
#define UART_BAUDRATE _REG(unsigned, 0x40002524) | |||
#define UART_BAUDRATE_1200 0x0004f000 | |||
#define UART_BAUDRATE_2400 0x0009d000 | |||
#define UART_BAUDRATE_4800 0x0013b000 | |||
#define UART_BAUDRATE_9600 0x00275000 | |||
#define UART_BAUDRATE_14400 0x003af000 | |||
#define UART_BAUDRATE_19200 0x004ea000 | |||
#define UART_BAUDRATE_28800 0x0075c000 | |||
#define UART_BAUDRATE_31250 0x00800000 | |||
#define UART_BAUDRATE_38400 0x009d0000 | |||
#define UART_BAUDRATE_56000 0x00e50000 | |||
#define UART_BAUDRATE_57600 0x00eb0000 | |||
#define UART_BAUDRATE_76800 0x013a9000 | |||
#define UART_BAUDRATE_115200 0x01d60000 | |||
#define UART_BAUDRATE_230400 0x03b00000 | |||
#define UART_BAUDRATE_250000 0x04000000 | |||
#define UART_BAUDRATE_460800 0x07400000 | |||
#define UART_BAUDRATE_921600 0x0f000000 | |||
#define UART_BAUDRATE_1M 0x10000000 | |||
#define UART_CONFIG _REG(unsigned, 0x4000256c) | |||
#define UART_CONFIG_HWFC __BIT(0) | |||
#define UART_CONFIG_PARITY __FIELD(1, 3) | |||
#define UART_PARITY_None 0 | |||
#define UART_PARITY_Even 7 | |||
</source></tab> | </source></tab> | ||
</tabs> | </tabs> | ||
<BR> | |||
<BR> | |||
'''Úlohy:''' <BR> | |||
1. Nájdite v [https://senzor.robotika.sk/mmp/nRF51_RM_v3.0.pdf datasheete k procesoru nRF51] adresu registra, ktorým nastavíme prenosovú rýchlosť a zistite akú hodnotu musíme do tohoto registra | |||
zapísať, aby bola rýchlosť 9600 Bd. | |||
<BR> | |||
2. Nahrajte do micro:bitu už preložený program [https://senzor.robotika.sk/mmp/program01.hex program01.hex] a skúste pomocou programu Terminal zistiť, akou rýchlosťou posiela dáta do počítača. | |||
Riadok 126: | Riadok 293: | ||
</tabs> | </tabs> | ||
* Python programovacie prostredie https://python.microbit.org | |||
<BR> | <BR> | ||
Riadok 151: | Riadok 319: | ||
'''Zoznam použitých blokov:''' | |||
* Instrument Control Toolbox | |||
** Serial Configuration | |||
** Serial Receiver | |||
* Simulink | |||
* ASCII to String | |||
* String to Single | |||
* Scope | |||
<BR> | |||
<BR> | |||
'''Úlohy:''' <BR> | |||
1. Upravte program v pythone tak, aby vysielal len jednu hodnotu avšak ako reťazec konštantnej dĺžky 4 bajty (napr. hodnotu 37 pošle ako 0037) ukončený znakom '\r'. | |||
Blok Serial Receiver totiž nedokáže prijímať rámce s premenlivou dĺžkou. | |||
<BR> | |||
2. Zostavte simulačnú schému podľa obrázku a predveďte, že dokážete prijímať údaje zo senzora v Simulinku. | |||
[[Súbor:SimulinkUARTreceive.png]] | |||
<BR> | |||
3. Doplňte obvod o jednoduchý filter prvého rádu a odfiltrujte zo signálu šum. Porovnajte so simuláciou. | |||
[[Súbor:SimulinkUARTreceiveFilter.png]] | |||
Aktuálna revízia z 06:52, 29. november 2023
Komunikácia a UART - praktická časť
Softvér a materiály na stiahnutie
- Nordic Semiconductor nRF51 Series Reference Manual (Version 3.0)
- Nástroj na testovanie komunikácie
- Terminal by Bray++, neinštaluje sa, len spustí.
- Terminal -- lokálna kópia
- Nástroj na kreslenie prijatých údajov
- Serial Plotter -- domovská stránka programu
- Lokálna kópia
Odkazy
- Ovládač pre Windows: https://os.mbed.com/handbook/Windows-serial-configuration
- Python programovacie prostredie https://python.microbit.org
1. Bare-metal prístup k programovaniu
Bare metal znamená, že budeme priamo programovať procesor bez využívania akýchkoľvek knižníc, takmer na strojovej úrovni. Vyžaduje si to do hĺbky preštudovať manuál k danému procesoru. Preto túto časť budeme chápať len ako ukážku, nebudeme to skutočne programovať.
Ak chceme v programe použiť funkciu printf na vysielanie znakov, musíme si ju doprogramovať. Jeden prístup predstavuje kompilátor avr-gcc pre procesory AVR. Stačí mať vlastnú implementáciu funkcií putc() a getc() a printf bude fungovať na ľubovoľnom vstupno-výstupnom zariadení.
#define BAUD 9600
#include <avr/io.h>
#include "uart.h"
#include <stdio.h>
...
FILE mystdout = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE);
int main(void)
{
uart_init(); // Inicializacia seriovej linky
stdout = &mystdout; // Odteraz funguje printf();
printf("Hello, world!");
return 0;
}
/* ************************************************************************* */
/* FileName : uart.h */
/* ************************************************************************* */
void uart_init( void );
void uart_putc( char c );
char uart_getc( void );
#include <avr/io.h>
#include <util/setbaud.h>
void uart_init( void )
{
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
#if USE_2X
UCSR0A |= _BV(U2X0);
#else
UCSR0A &= ~(_BV(U2X0));
#endif
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
UCSR0B = _BV(RXEN0) | _BV(TXEN0); /* Enable RX and TX */
}
void uart_putc(char c)
{
if (c == '\n')
{
uart_putc('\r');
}
loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
UDR0 = c;
}
char uart_getc(void) {
loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
return UDR0;
}
Iný prístup je v jazyku C pre procesory ARM, kde je implementácia funkcie printf rozdelená na dve časti: jedna časť je nezávislá od výstupného zariadenia a postará sa o vstupné dáta vrátane ich formátovania, takže máme k dispozícii hotovú postupnosť znakov. Druhá časť, ktorá zabezpečí samotné odostlanie znakov je samozrejme závislá na hardvéri. Akýkoľvek program, ktorý chce funkciu printf využívať, musí zabezpečiť vlastnú implementáciu funkcie print_buf definovanej nasledovne
void print_buf(const char *buf, int n)
Jej vstupom je reťazec (postupnosť) znakov a počet znakov, takže v princípe stačí v jednoduchej slučke poslať znaky na prslušné výstupné zariadenie, v našom prípade na obvod UART. V zložitejšícch aplikáciach na to využijeme služby nejakého operačného systému.
#include "microbian.h"
#include "hardware.h"
#include "serial.h"
#include "lib.h"
#include "accel.h"
static void main(int n)
{
int x, y, z;
timer_delay(1000);
accel_start();
while (1)
{
timer_delay(200);
accel_reading(&x, &y, &z);
printf("%d,%d,%d\n", x, y, z);
}
}
void init(void)
{
serial_init();
timer_init();
i2c_init(I2C_INTERNAL);
start("Main", main, 0, STACK);
}
#include "hardware.h"
void serial_init(void);
void serial_puts(const char *s);
/* Pins to use for serial communication */
#define TX USB_TX
#define RX USB_RX
int txinit; /* UART ready to transmit first char */
/* serial_init -- set up UART connection to host */
void serial_init(void)
{
UART_ENABLE = UART_ENABLE_Disabled;
UART_BAUDRATE = UART_BAUDRATE_9600; /* 9600 baud */
UART_CONFIG = FIELD(UART_CONFIG_PARITY, UART_PARITY_None);
/* format 8N1 */
UART_PSELTXD = TX; /* choose pins */
UART_PSELRXD = RX;
UART_ENABLE = UART_ENABLE_Enabled;
UART_STARTTX = 1;
UART_STARTRX = 1;
UART_RXDRDY = 0;
txinit = 1;
}
/* serial_putc -- send output character */
void serial_putc(char ch)
{
if (! txinit) {
while (! UART_TXDRDY) { }
}
txinit = 0;
UART_TXDRDY = 0;
UART_TXD = ch;
}
/* serial_puts -- send a string character by character */
void serial_puts(const char *s)
{
while (*s != '\0')
serial_putc(*s++);
}
/* Časť súboru hardware.h s definíciami týkajúcimi sa UART rozhrania */
/* UART */
/* Interrupts */
#define UART_INT_RXDRDY 2
#define UART_INT_TXDRDY 7
#define UART_BASE _BASE(0x40002000)
/* Tasks */
#define UART_STARTRX _REG(unsigned, 0x40002000)
#define UART_STARTTX _REG(unsigned, 0x40002008)
/* Events */
#define UART_RXDRDY _REG(unsigned, 0x40002108)
#define UART_TXDRDY _REG(unsigned, 0x4000211c)
/* Registers */
#define UART_INTENSET _REG(unsigned, 0x40002304)
#define UART_INTENCLR _REG(unsigned, 0x40002308)
#define UART_ENABLE _REG(unsigned, 0x40002500)
#define UART_ENABLE_Disabled 0
#define UART_ENABLE_Enabled 4
#define UART_PSELTXD _REG(unsigned, 0x4000250c)
#define UART_PSELRXD _REG(unsigned, 0x40002514)
#define UART_RXD _REG(unsigned, 0x40002518)
#define UART_TXD _REG(unsigned, 0x4000251c)
#define UART_BAUDRATE _REG(unsigned, 0x40002524)
#define UART_BAUDRATE_1200 0x0004f000
#define UART_BAUDRATE_2400 0x0009d000
#define UART_BAUDRATE_4800 0x0013b000
#define UART_BAUDRATE_9600 0x00275000
#define UART_BAUDRATE_14400 0x003af000
#define UART_BAUDRATE_19200 0x004ea000
#define UART_BAUDRATE_28800 0x0075c000
#define UART_BAUDRATE_31250 0x00800000
#define UART_BAUDRATE_38400 0x009d0000
#define UART_BAUDRATE_56000 0x00e50000
#define UART_BAUDRATE_57600 0x00eb0000
#define UART_BAUDRATE_76800 0x013a9000
#define UART_BAUDRATE_115200 0x01d60000
#define UART_BAUDRATE_230400 0x03b00000
#define UART_BAUDRATE_250000 0x04000000
#define UART_BAUDRATE_460800 0x07400000
#define UART_BAUDRATE_921600 0x0f000000
#define UART_BAUDRATE_1M 0x10000000
#define UART_CONFIG _REG(unsigned, 0x4000256c)
#define UART_CONFIG_HWFC __BIT(0)
#define UART_CONFIG_PARITY __FIELD(1, 3)
#define UART_PARITY_None 0
#define UART_PARITY_Even 7
Úlohy:
1. Nájdite v datasheete k procesoru nRF51 adresu registra, ktorým nastavíme prenosovú rýchlosť a zistite akú hodnotu musíme do tohoto registra
zapísať, aby bola rýchlosť 9600 Bd.
2. Nahrajte do micro:bitu už preložený program program01.hex a skúste pomocou programu Terminal zistiť, akou rýchlosťou posiela dáta do počítača.
2. Programovanie vo vyššom programovacom jazyku
Teraz to isté spravíme vo vyššom programovacom jazyku, bude to Python:
from microbit import *
uart.init(baudrate=115200, bits=8, parity=None, stop=1)
while True:
accX = accelerometer.get_x()
uart.write('%d\r\n' % (accX))
sleep(100)
display.set_pixel(1,1,5)
sleep(100)
display.set_pixel(1,1,0)
- Python programovacie prostredie https://python.microbit.org
Úlohy:
1. Zmeňte prenosovú rýchlosť na 9600 Bd, skúste zmeniť aj iné parametre a otestujte ako sa to prejaví na prijímaných dátach.
2. Zobrazte v programe SerialPlot všetky tri osi akcelerometra a predveďte, že meria skutočne aj gravitačné zrýchlenie.
Postup:
- upravte program v Pythone nasledovne:
- program má poslať do PC tri čísla -- zrýchlenie v osi x-, y- a z-. Čísla majú byť oddelené čiarkou a na konci má byť nový riadok ('\r\n').
- program preneste do micro:bitu
- spustite program Terminal, nastavte komunikačné parametre a stlačte Connect - v terminálovom okne by ste mali vidieť prijaté znaky. Ak je formát vyhovujúci, odpojte port (Disconnect) a pokračujte ďalej
- Nastavte parametre pre grafický program SerialPlot. Po spustení programu SerialPlot by ste mali vidieť grafické priebehy.
3. Simulink
No a na záver vyskúšame programovať v prostredí Simulink
Zoznam použitých blokov:
- Instrument Control Toolbox
- Serial Configuration
- Serial Receiver
- Simulink
- ASCII to String
- String to Single
- Scope
Úlohy:
1. Upravte program v pythone tak, aby vysielal len jednu hodnotu avšak ako reťazec konštantnej dĺžky 4 bajty (napr. hodnotu 37 pošle ako 0037) ukončený znakom '\r'.
Blok Serial Receiver totiž nedokáže prijímať rámce s premenlivou dĺžkou.
2. Zostavte simulačnú schému podľa obrázku a predveďte, že dokážete prijímať údaje zo senzora v Simulinku.
3. Doplňte obvod o jednoduchý filter prvého rádu a odfiltrujte zo signálu šum. Porovnajte so simuláciou.
Serial Terminal by Bray
Na testovanie a prvé pokusy so sériovým rozhraním sa vám určite zíde aj nejaký terminálový program, masochisti môžu použiť aj Hyperterminál z Windows. Terminál je jednoduchý program, v ktorom sa zobrazujú všetky prijaté znaky a naopak, je možné nejaké iné znaky odvysielať. Dajú sa samozrejme aj nastaviť základné komunikačné parametre.
Ukážka práce s Terminalom vrátane správneho nastavenia parametrov
Serial Plotter
Serial Plotter je trocha sofistikovanejší program ako Terminal, jeho úlohou je zakresliť graficky všetky prijaté informácie. Najjednoduchšie je posielať mu čísla, pričom ich môže byť aj viac, oddelených čiarkami. Každá jedna n-tica hodnôt musí končíť znakom pre nový riadok. V knižnici Serial použite bloky Serial Write Number pre čísla, Serial Write String pre čiarky a Serial Write Line pre ukončenie riadka. Neposielajte hodnoty príliš často, aby sa nepreplnil vstupný buffer.