Communicating with a micro-controller at runtime, is a very useful facility. It can be used for debugging, or to send commands etc. One of the easiest available protocol to communicate is UART. It requires a pin for transmit and a pin for receive, and the GROUND connection. There are many available programs that allow us to communicate using UART on the serial port, or using a usb-serial adapter. e.g. hyperterminal, minicom, etc.
However, not all microcontrollers have UART ports in built.
i was taking a look at the UART protocol, and it seemed pretty simple to implement. So i gave it a go, and was zapped when it just worked the first time :).
Below is a little app that accepts 2 byte commands. Toggles LATD1 when it receives the command "TG", and echoes back the command after its done. Invert flag is provided. ( Inversion may be needed if we are not working directly with a real serial port). Tested with minicom @9600 baud, with hardware-flow-control OFF, so that it sends the chars we type.
It is tested on the PIC18F4550, will need modifications to run on other microcontrollers.
Its also available as a module to include at https://github.com/manojmo/pic_micro
However, not all microcontrollers have UART ports in built.
i was taking a look at the UART protocol, and it seemed pretty simple to implement. So i gave it a go, and was zapped when it just worked the first time :).
Below is a little app that accepts 2 byte commands. Toggles LATD1 when it receives the command "TG", and echoes back the command after its done. Invert flag is provided. ( Inversion may be needed if we are not working directly with a real serial port). Tested with minicom @9600 baud, with hardware-flow-control OFF, so that it sends the chars we type.
It is tested on the PIC18F4550, will need modifications to run on other microcontrollers.
Its also available as a module to include at https://github.com/manojmo/pic_micro
/* * File: main.c * Author: manoj * Writing to uart * Created on September 27, 2014, 6:01 PM */ #include#include #include // PLL with pre-scaler and post-scale options is a way to derive multiple // freq from the same source, e.g. for low=6Mhz/high=48Mhz speed USB and for MCU clock // Input to PLL has to be 4 Mhz and its output is 96 MHz // So, for e.g. if we are using exernal 20 MHz osc, its o/p has to be // divided by 5 to get 4 Mhz input for PLL // PLLDIV is prescaler, o/p has to be 4MHz // CPUDIV and USBDIV are postscalers, input is 96Mhz #pragma config PLLDIV = 5 // (20 MHz crystal on PICDEM FS USB board) #pragma config CPUDIV = OSC1_PLL2 #pragma config USBDIV = 2 // Clock source from 96MHz PLL/2 #pragma config FOSC = HSPLL_HS #pragma config IESO = OFF #pragma config WDT = OFF #pragma config STVREN = ON #pragma config LVP = ON #pragma config BOR = ON #pragma config MCLRE = ON #pragma config PWRT = OFF #pragma config PBADEN = OFF // Effective CPU Freq, considering PLL and CPUDIV. Needed for the delay routines #define _XTAL_FREQ 48000000 #define UART_BIT_TIME 104 // us. inverse gives the bit-rate #define PIN_UART_TX LATD4 // output #define PIN_UART_RX PORTDbits.RD5 // input uint8_t UART_INVERTED = 0; // If inverted, low and high states will be inverted uint8_t HIGH_STATE = 1; uint8_t LOW_STATE = 0; // flexible way to set some params. void uart_init( uint8_t is_inverted){ UART_INVERTED = is_inverted; if( is_inverted){ HIGH_STATE = 0; LOW_STATE = 1; } } // start of transmission void uart_start_tx(){ PIN_UART_TX = HIGH_STATE; } // end of transmission void uart_end_tx(){ PIN_UART_TX = HIGH_STATE; } // write a char void uart_write( char c){ // start bit PIN_UART_TX = LOW_STATE; __delay_us( UART_BIT_TIME); uint8_t bit_pos = 0; // transmit bits, LSB first while (bit_pos < 8) { uint8_t currbit = c & 0x01; PIN_UART_TX = UART_INVERTED ? ! currbit : currbit; __delay_us( UART_BIT_TIME); bit_pos++; c = c >> 1; } // stop bit PIN_UART_TX = HIGH_STATE; __delay_us( UART_BIT_TIME); } // Read specified number of chars and put them into holder array void uart_read( uint8_t len, char holder[] ){ uint8_t i; uint8_t bit_pos; // loop and read len number of chars. for( i=0; i< len; i++){ // Wait for idle state to change, i.e. start bit while( PIN_UART_RX == HIGH_STATE); // start bit __delay_us( UART_BIT_TIME); // read bits, LSB first bit_pos = 0; char c = 0; while (bit_pos < 8) { uint8_t currbit = UART_INVERTED ? ! PIN_UART_RX : PIN_UART_RX; c = c | (currbit << bit_pos); __delay_us( UART_BIT_TIME); bit_pos++; } holder[i] = c; // stop bit __delay_us( UART_BIT_TIME); } } // write a string, optionally of specified len. // if null terminated, len can be -1 void uart_writestr( char str[], int len ){ int i; for( i=0; i< len || len == -1; i++){ char curr = str[i]; if( curr == '\0'){ break; } uart_write( curr); } } // process the command we received void process_cmd(char cmd[] ){ if( strncmp( cmd, "TG", 2) == 0){ LATD1 ^= 1; } } /* * */ int main(int argc, char** argv) { TRISDbits.RD4 = 0; //TX pin set as output TRISDbits.RD5 = 1; //RX pin set as input TRISDbits.RD1 = 0; // command output uart_init(1); // invert uart_start_tx(); char cmd[2]; // array to hold received command. while(1){ uart_read( 2, cmd); // read a command, specified bytes long process_cmd( cmd); uart_writestr( cmd, 2); // echo it back } }
No comments:
Post a Comment