Przydatność różnych modułów, szczególnie zawierających rozbudowane (w sensie liczby wyprowadzeń) elementy przewidziane do montażu SMD nie podlega dyskusji. Takimi elementami z pewnością są mikrokontrolery. Sam mikrokontroler ma kilkadziesiąt delikatnych wyprowadzeń. Taki komponent musi zostać do czegoś przylutowany. Jak przylutowany, to koniecznie należy „wyprodukować” odpowiednią płytkę PCB. Warto przewidzieć na tej płytce jakieś dodatkowe elementy, które często występują w środowisku testowym mikrokontrolera. Zdecydowałem się na zabudowę zestawu LED'ów oraz interfejsu RS232. Nieodzownym również elementem jest przyłącze do programatora pamięci FLASH wewnątrz mikrokontrolera. Pozostałe porty są wyprowadzone na złącze szpilkowe, które pozwoli na integrację modułu z płytą “Solderless Breadboard”. Tak określone wymagania spełnia moduł, którego schemat przedstawiają kolejne ilustracje. Ilustracja 1 zawiera mikrokontroler i niezbędne do jego działania elementy: zespół resetowania, rezonator kwarcowy do „napędzania” procesora oraz przyłącze do programatora ISP.
W konstrukcji zostało przewidzianych 8 LED'ów, które są przyłączone do portu B mikrokontrolera. Wybór portu jest podyktowany tym, że port ten jest współużywany również przez programator ISP i w trakcie jego działania nie mogą być zakłócane odpowiednie linie. Zespół LED'ów odseparowany od mikrokontrolera przez układ ULN2803 nie generuje żadnych sygnałów na liniach programatora. Dodatkowo odciąża prądowo port mikrokontrolera (ilustracja 2). Zastosowane rozwiązanie oznacza również, że zapalenie diody LED wymaga ustawienia na porcie stanu wysokiego. Kolejnym istotnym elementem jest interfejs RS232 pozwalający na eksperymenty z transmisją szeregową (ilustracja 3). Zastosowany jest tu układ ST3232, będący mutacją znanego układu MAX232, który może być zasilany napięciem obniżonym. Pozwala to na eksperymenty z zasilaniem procesora ze źródła napięcia o wartości zarówno +5V jak i +3,3V. Pozostałe niewykorzystane w module wyprowadzenia są przyłączone do złącz szpilkowych przewidzianych do stworzenia elektrycznego kontaktu tych portów z płytą „dziurkowaną” (ilustracja 4). Zgodnie ze schematem połączeń, zaprojektowana jest niewielka płytka PCB (ilustracje 5, 6, 7). Po przylutowaniu wszystkich elementów powstaje wyrób finalny (ilustracja 9). Tekst programu testowego dla modułu.
Kod: Zaznacz cały
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#define FALSE 0
#define TRUE 1
#define Cr 0x0D
#define Lf 0x0A
#define LEDPort PORTB
#define LEDDirPort DDRB
#define USART_Speed 47 // USART BAUD Rate Generator fosc=7.3728 MHz , 9600 bps
#define StandardTimerDelay 24
#define nop() __asm__ __volatile__ ("nop")
#define IdleState 0
#define BusyState 1
#define TXDBuffSize 64
#define RXDBuffSize 16
typedef struct { uint8_t CycFr ;
uint8_t CycTo ;
uint8_t State ;
uint8_t Buffer [ TXDBuffSize ] ;
} TXDRecT ;
typedef struct { uint8_t CycFr ;
uint8_t CycTo ;
uint8_t Buffer [ RXDBuffSize ] ;
} RXDRecT ;
static volatile TXDRecT TXDRec ;
static volatile RXDRecT RXDRec ;
static uint8_t TimerCounter ;
static uint8_t LEDData ;
static uint8_t HelloTxt [ ] PROGMEM = "\r\nCzesc koles z www.microgeek.eu:\r\nNacisnij jakis znak:" ;
static uint8_t ProcessChPrompt [ ] PROGMEM = "Nacisnales : " ;
static uint8_t ControlCharText [ ] PROGMEM = "znak kontrolny" ;
SIGNAL ( TIMER0_OVF_vect )
{
TimerCounter ++ ;
if ( TimerCounter > StandardTimerDelay )
{
TimerCounter = 0 ;
LEDData ++ ;
LEDPort = LEDData ;
} /* if */ ;
} /* TIMER0_OVF_vect */
SIGNAL ( SIG_UART_RECV )
{
uint8_t RecVCh ;
/*-------------------------------------------------------------------------*/
RecVCh = UDR ;
RXDRec . Buffer [ RXDRec . CycTo ] = RecVCh ;
RXDRec . CycTo ++ ;
if ( RXDRec . CycTo >= RXDBuffSize )
RXDRec . CycTo = 0 ;
} /* SIG_USART_RECV */
SIGNAL ( SIG_UART_TRANS )
{
if ( TXDRec . CycFr == TXDRec . CycTo )
{
TXDRec . State = IdleState ;
} /* if ... */
else
{
UDR = TXDRec . Buffer [ TXDRec . CycFr ] ;
TXDRec . CycFr ++ ;
if ( TXDRec . CycFr >= TXDBuffSize )
TXDRec . CycFr = 0 ;
} /* if ... else */ ;
} /* SIG_USART_TRANS */
static void USARTSoftwareInit ( void )
{
RXDRec . CycFr = 0 ;
RXDRec . CycTo = 0 ;
TXDRec . CycFr = 0 ;
TXDRec . CycTo = 0 ;
TXDRec . State = IdleState ;
} /* USARTSoftwareInit */
static void SendSerial ( uint8_t SerialCh )
{
uint8_t NextInx ;
/*-------------------------------------------------------------------------*/
cli ( ) ;
if ( TXDRec . State == IdleState )
{
TXDRec . State = BusyState ;
UDR = SerialCh ;
sei ( ) ;
} /* if ... */
else
{
for ( ; ; )
{
NextInx = TXDRec . CycTo + 1 ;
if ( NextInx >= TXDBuffSize )
NextInx = 0 ;
if ( NextInx != TXDRec . CycFr )
break ;
sei ( ) ;
nop ( ) ;
nop ( ) ;
cli ( ) ;
} /* for */ ;
TXDRec . Buffer [ TXDRec . CycTo ] = SerialCh ;
TXDRec . CycTo ++ ;
if ( TXDRec . CycTo >= TXDBuffSize )
TXDRec . CycTo = 0 ;
sei ( ) ;
} /* if ... else */ ;
} /* SendSerial */
static void SendSerialFlashTxt ( uint16_t String )
{
uint8_t Data ;
/*-------------------------------------------------------------------------*/
for ( ; ; )
{
Data = pgm_read_byte_near ( String ) ;
if ( Data )
SendSerial ( Data ) ;
else
break ;
String ++ ;
} /* for */ ;
} /* SendSerialFlashTxt */
static void SendNewLine ( void )
{
SendSerial ( Cr ) ;
SendSerial ( Lf ) ;
} /* SendNewLine */
static uint8_t SerialDataPresent ( void )
{
if ( RXDRec . CycFr == RXDRec . CycTo )
return ( FALSE ) ;
else
return ( TRUE ) ;
} /* SerialDataPresent */
static uint8_t GetSerial ( void )
{
uint8_t Ch ;
/*-------------------------------------------------------------------------*/
Ch = RXDRec . Buffer [ RXDRec . CycFr ] ;
RXDRec . CycFr ++ ;
if ( RXDRec . CycFr >= RXDBuffSize )
RXDRec . CycFr = 0 ;
return Ch ;
} /* GetSerial */
static void HardwareInit ( void )
{
TIMSK = ( 1 << TOIE0 ) ;
TCCR0 = ( 1 << CS02 ) ;
UCSRA = 0 ;
UCSRB = ( 1 << RXCIE ) | ( 1 << TXCIE ) | ( 1 << RXEN ) | ( 1 << TXEN ) ;
UCSRC = ( 1 << URSEL ) | ( 1 << UCSZ1 ) | ( 1 << UCSZ0 ) ;
UBRRH = ( uint8_t ) ( ( USART_Speed >> 8 ) & 0xFF ) ;
UBRRL = ( uint8_t ) ( USART_Speed & 0xFF ) ;
} /* HardwareInit */
static void EnvirInit ( void )
{
LEDDirPort = 0xFF ;
LEDPort = 0 ;
} /* EnvirInit */
static void SoftwareInit ( void )
{
USARTSoftwareInit ( ) ;
TimerCounter = 0 ;
LEDData = 0 ;
} /* SoftwareInit */
static void ProcessChar ( uint8_t Ch )
{
SendSerialFlashTxt ( ( uint16_t ) ProcessChPrompt ) ;
if ( Ch >= 32 )
{
SendSerial ( Ch ) ;
} /* if ... */
else
{
SendSerialFlashTxt ( ( uint16_t ) ControlCharText ) ;
} /* if ... else */ ;
SendNewLine ( ) ;
} /* ProcessChar */
int main ( void )
{
HardwareInit ( ) ;
EnvirInit ( ) ;
SoftwareInit ( ) ;
sei ( ) ;
SendNewLine ( ) ;
SendSerialFlashTxt ( ( uint16_t ) HelloTxt ) ;
SendNewLine ( ) ;
SendNewLine ( ) ;
for ( ; ; )
{
if ( SerialDataPresent ( ) )
{
ProcessChar ( GetSerial ( ) ) ;
} /* if */ ;
} /* for */ ;
return ( 0 ) ;
} /* main */
Załącznik: program testowy, projekt w AVRSTUDIO