Hello everyone
I've been working with UART communication and typically use the standard 8N1 configuration. However, I recently came across a scenario where I want to configure UART for 5 data bits (5N1). I've already written code to handle UART communication for 8N1, but I'm unsure about how to transfer only 5 bits of data.
Can you provide code examples on how to transmitting and receiving data for 5N1 ?
#include <xc.h>
#include <stdio.h>
#include"config.h"
void initializeOscillator(void);
void initializeEUSART1(void);
/*****
* NOTE: This function configures the oscillator settings for the microcontroller.
* It sets the IRCF bits to 110 for HF-INTOSC/2 (8 MHz, default).
*****/
void initializeOscillator(void)
{
OSCCON = 0x60; // Set IRCF bits to 110 for HF-INTOSC/2 (8 MHz, default)
OSCCON2 = 0x00;
OSCTUNE = 0x00;
REFOCON = 0x00;
}
void initializePort() {
// Set LATx registers to initial states (all low)
LATA = 0x00;
LATB = 0x00;
LATC = 0x00;
LATD = 0x00;
LATE = 0x00;
// Set TRISx registers to configure pins as outputs (all output)
TRISA = 0x00;
TRISB = 0x00; // RB0 is RED, RB1 is YELLOW and RB2 is GREEN LED
TRISC = 0x80; // RC7 is TX and RC6 TX
TRISD = 0x00;
TRISE = 0x00;
// Additional configuration for unused peripherals
ANCON0 = 0x00; // Set all analog pins to digital mode
ANCON1 = 0x00; // Set all analog pins to digital mode
CM1CON = 0x00; // Turn off Comparator 1
CM2CON = 0x00; // Turn off Comparator 2
ADCON0 = 0x00; // Disable A/D conversion
ADCON1 = 0x00; // Disable A/D conversion
ADCON2 = 0x00; // Disable A/D conversion
}
/*****
*
* NOTE: This function configures the EUSART1 settings for communication.
*
*****/
void initializeUART1() {
// Configure BAUDCON1 register
// Bit 7: ABDOVF = 0 (Auto-Baud Acquisition Rollover Status bit - Cleared in software)
// Bit 6: RCIDL = 0 (Receive Operation Idle Status bit - Receive operation is active)
// Bit 5: RXDTP = 0 (Received Data Polarity Select bit - Receive data is not inverted)
// Bit 4: TXCKP = 0 (Clock and Data Polarity Select bit - Idle state for transmit is high level)
// Bit 3: BRG16 = 1 (16-Bit Baud Rate Register Enable bit - 16-bit Baud Rate Generator)
// Bit 2: Unimplemented: Read as ?0? (Reserved, read as '0')
// Bit 1: WUE = 0 (Wake-up Enable bit - RX pin is not monitored or rising edge is detected)
// Bit 0: ABDEN = 0 (Auto-Baud Detect Enable bit - Baud rate measurement is disabled or completed)
BAUDCON1 = 0b00001000; // Set BRG16 bit to 1 (16-Bit Baud Rate Register Enable)
// Calculate and set SPBRG1 for a baud rate of approximately 9600 at 8 MHz
SPBRG1 = 207;
SPBRGH1 = 0;
// TXSTA1 register configuration
// Bit 7: CSRC = 0 (Clock Source Select bit - Don't care in Asynchronous mode)
// Bit 6: TX9 = 0 (8-bit transmission)
// Bit 5: TXEN = 1 (Transmit is enabled)
// Bit 4: SYNC = 0 (Asynchronous mode)
// Bit 3: SENDB = 0
// Bit 2: BRGH = 1 (High-speed baud rate)
// Bit 1: TRMT = 1 (TSR is empty initially)
TXSTA1 = 0b00100100; // Configure TXSTA1 register
// RCSTA1 register configuration
// Bit 7: SPEN = 1 (Serial Port Enable bit - Serial port is enabled)
// Bit 6: RX9 = 0 (8-bit reception)
// Bit 5: SREN = 0 (Single Receive Enable bit - Don't care in Asynchronous mode)
// Bit 4: CREN = 1 (Continuous Receive Enable bit - Enables receiver)
// Bit 3: ADDEN = 0 (Address Detect Enable bit - Don't care in Asynchronous mode)
// Bit 2: FERR = 0 (Framing Error bit - No framing error)
// Bit 1: OERR = 0 (Overrun Error bit - No overrun error)
RCSTA1 = 0b10010000; // Configure RCSTA1 register
}
void hardwareInitialize() {
// Initialize the oscillator
initializeOscillator();
// Initialize Port Pins
initializePort();
// Initialize Uart1
initializeUART1();
}
/*****
*
* NOTE: This function waits until the transmitter buffer is empty (TXIF is set)
* and then sends the character by placing it in the TXREG1 register.
*
*****/
void UARTWrite(char Character)
{
// Wait until the transmitter buffer is empty (TXIF is set)
while (TXIF == 0);
// Send the character by placing it in the TXREG1 register
TXREG1 = Character;
}
/*****
*
* NOTE: This function waits until the receiver buffer is full (RCIF is set)
* and then reads the received character from the RCREG1 register.
*
*****/
char UARTRead(void)
{
// Wait until the receiver buffer is full (RCIF is set)
while (RCIF == 0);
// Read the received character from the RCREG1 register
return RCREG1;
}
/*****
*
* main - Main program function
*
*****/
void main(void)
{
// Initialize hardware
hardwareInitialize();
// Delay for 5 seconds
__delay_ms(5000);
while (1)
{
// Define a character to send
char Character = 'U';
char ReceivedChar;
ReceivedChar = UARTRead(); // Read a command from UART
UARTWrite(ReceivedChar); // Send the command back
// Delay for 5 seconds before the next transmission
__delay_ms(5000);
}
}
From the look of your code, you are using an 8 bit PIC. AFAIK there aren't any 8 bit PICs with 5 bit UART support (as mechanical teletypes were already a dead technology by the date Microchip was founded), but you can send 5 bit data by OR masking the three high bits to 1. This gives you too many stop bits (5N4) but is compatible with a 5N1 receiver albeit with only 70% of the peak characters per second for the same baud rate. This does *NOT* work for receiving 5N1 data unless there are at least three extra idle bits between characters, so if you need bidirectional comms or the full data rate your only option is to write a 5 bit capable bit-banged software UART.
I suspect there are 3 viable options:
1) Bit bang for 5-bit,
2) Pack your 5-bit data into 8-bit bytes, or
3) Pad your data to give 8-bits.
I suspect you are not interested in bit banging, but here's an example I got from Mike (K8LH) years ago in case you are curious of what it looks like in PIC Assembly. It can be adapted to 5 bit, but you will need to also get the receive end (e.g., Get232).
;******************************************************************************
; PUT232
; Put232 (9600 baud) -- Mike McLaren, K8LH (Jan-09)
;******************************************************************************
Put232
movlb 2
movwf txbyte ; save Tx data byte
movlw 10 ; 1 start + 8 data + 1 stop bit
movwf bit_ctr ; setup bit counter
bcf status,0 ; C = 0 (start bit)
DelayCy (104*usecs-10) ; 104 usecs minus 10 cycles(added)
goto SendBit ; send start bit
NextBit
DelayCy (104*usecs-10) ; 104 usecs minus 10 cycles
bsf status,0 ; always shift in a 'stop' bit
rrf txbyte,f ; put data bit in Carry
SendBit
movf LATD,W ; read port
iorlw 1<<1 ; set Ser_out pin bit to 1
btfss status,0 ; if data bit = 1 skip, else
xorlw 1<<1 ; set Ser_out pin bit to 0
movwf LATD ; precise update intervals
decfsz bit_ctr,f ; done? yes, skip, else
goto NextBit ; send next bit
retlw 0 ;
"DelayCy" is a macro. You will need to insert an appropriate delay for your baud rate.
Stop bit is a "1":
So, it's very simple, use the 8-bit UART, set the 3 MSB to 1, so the last 3 bits and the stop are merged together:
TX = DATA_5B | 0xE0;
This makes the uart to send:
Start D0 D1 D2 D3 D4 1 1 1 Stop
A 5-bit uart receiver will take D5 as the stop bit, the remaining data is 1 so no new start will happen.
This "hack" will work with any number of bits between 1 and 8, but the PIC will be still sending 8bits, so the effective data rate won't be faster, if that was you target.
I've come across numerous documents and online tutorials that discuss the ability to transfer data with 5 to 9 bits, but most examples and practical applications seem to focus on the standard 8-bit configuration. This has sparked my curiosity about experimenting with 5 or 6 data bits. When shifting the data position to achieve 5 bits, there's still the transmission of 8 bits.
Could you share your experiences on how one might effectively experiment with data configurations of 5 or 6 bits, and what considerations are important when attempting such configurations? Additionally, have you encountered any real-world scenarios where non-standard data bit configurations were beneficial
Could you share your experiences on how one might effectively experiment with data configurations of 5 or 6 bits, and what considerations are important when attempting such configurations? Additionally, have you encountered any real-world scenarios where non-standard data bit configurations were beneficial
Just bit-bang and set bit_ctr to whatever you want +2. As mentioned, you need the Get232 code, which has a very similar structure.
Real world? PIC's hardware does allow 9-bit.
Read the datasheet of your microcontroller.
Some microcontrollers can be set up to do 5 bit data with the U(s)ART.
Could you share your experiences on how one might effectively experiment with data configurations of 5 or 6 bits,
As others have already said you can only configure your UART for 5 bit data if the UART supports this. Some do, some don't. The code you posted suggest you are using a PIC of some type, but you haven't told us which one. If your UART does not support 5 bit operation, then you will have to bit bang the data i.e. software emulation of the UART.
Bit banging works adequately for "low baudrates" (and "low" depends on the uC you use and how much other things it has to do)
And as other's have already mentioned, pre-formatting the data works, and in it's simplest form you will then just send the data with 4 stop bits, but any "receiving end" should be able to handle that. If you want to send more data, and can't afford to send 5 stop bits for each byte, then you can use dirty tricks such as resetting your U(s)ART after the 5 data bits have been sent.
Receiving 5N1 data is easy if there is enough room between the bytes, but if it's sent as a continuous 5n1 steam, then it's probably either bitbanging or using a U(s)ART that supports 5-bit data.
I've come across numerous documents and online tutorials that discuss the ability to transfer data with 5 to 9 bits, but most examples and practical applications seem to focus on the standard 8-bit configuration. This has sparked my curiosity about experimenting with 5 or 6 data bits.
When shifting the data position to achieve 5 bits, there's still the transmission of 8 bits.
Nope, not if the UART supports 5 bits. (see #3)
Could you share your experiences on how one might effectively experiment with data configurations of 5 or 6 bits, and what considerations are important when attempting such configurations?
Err ? Find UARTS that supports the 5 or 6 bits you seek, and try them ?
Additionally, have you encountered any real-world scenarios where non-standard data bit configurations were beneficial
The obvious saving is time. Other reasons may be more obtuse, like if you wanted to avoid casual hacking, or lock customers into your systems...
These modes are historic, as in
really historic...
https://en.wikipedia.org/wiki/Baudot_codeSo you can see where 5 bit UART came from.
Mid-range PIC's do not support 5-bit UART. Based on the TS's latest post, I suspect this is just a "what if" waste of time, as the TS has failed to give any specifics whatsoever.
A couple notes:
- The OP didn't bother to say which MCU they were trying to use and made people guess from the posted piece of code. All we know is that it looks like a PIC supported by the XC compiler, probably an 8-bit PIC and XC8, although I'm not even sure. Frankly I didn't bother checking out if the few registers used in the code were indicative of a particular PIC model, there are literally hundreds.
- If it turns out it doesn't natively support 5-bit data frames, then as said above, you could use some tricks (with limitations) or just bit-bang it (probably the easiest and making the most sense).
- We don't know what baud rate nor what system clock the OP is dealing with, so the bit-banging option may or may not be an option. Also, depending on which interrupts are enabled, it may require some particular care, like disabling interrupts while transmitting/receiving, or selectively disabling the ones appropriate, not completely trivial either.
Not to sound like a free lecture, but if you want more accurate, to-the-point answers while making people waste less time, giving more accurate requirements/context will go a long way. Actually, properly defining a problem is often 80% of the solution.
I apologize for not mentioning my microcontroller earlier. I'm using a PIC18F45K80. After reviewing the datasheet, specifically in Section 22.1 on page 327, it appears to me that this microcontroller only supports 8-bit or 9-bit communication
Quote from: Kittu20 on Today at 07:26:59 amAdditionally, have you encountered any real-world scenarios where non-standard data bit configurations were beneficial
My first project out of college involved interfacing a mainframe to a newswire that ran a 6bit version of baudot. That was 1981. I haven't seen anything shorter than 7 bits since, despite much of my career revolving round async UART communications.
I suspect there are 3 viable options:
1) Bit bang for 5-bit,
2) Pack your 5-bit data into 8-bit bytes, or
3) Pad your data to give 8-bits.
....
... 4) send the data in 40-bit (8-byte) buffers (or 8 x 5-bit transmissions at a time).