skip to main |
skip to sidebar
Running TX433 and RX433 RF modules with AVR microcontrollers
Sometimes in embedded design you may want to go wireless. Might be you will want to log various readings of remotely placed sensors, or simply build a remote control for robot or car alarm system.
Radio communications between two AVR microcontrollers can be easy when specialized modules are used. Lets try to run very well known RF modules TX433 and RX433 that (or similar) can be found almost in every electronics shop and pair of them cost about ~15 bucks.
Transmitter and receiver modules are tuned to work correctly at 433.92MHz. Transmitter can be powered from 3 to 12V power supply while receiver accepts 5V. 5V is common for AVR microcontrollers so no problems with interfacing. Modules don't require addition components – just apply power and connect single data line to send information to/from and that's it. For better distances apply 30 – 35cm antennas. Modules use Amplitude-Shift Keying(ASK) modulation method and uses 1MHz bandwidth.
I have constructed two separate circuits for testing on Atmega8 microcontrollers.
Transmitter
Receiver
For testing I have used a prototyping board and breadboard.
As you can see I have used one LED for indicating RF activity. Ok enough about hardware part – actually there is nothing more to say – circuits are simple.
Lets move on to software part. Radio transmission is a bit more complicated than wired communications because you never know what radio signals are present on air. So all matters how transmitted signal is encoded. And this is a part where you have many choices: use hardware encoding like USART or write your own based on one of many ending methods like NRZ, Manchester etc. In my example I have used AVR USART module to form data packs. Using hardware encoders solves many problems like synchronization, start and stop, various signal checks. But as long as I was practising you cannot rely on plain USART signal. Here you can actually improvize by adding various checks and so on.
I decided to form 4 byte data packages in order to send one byte information. These include:
• one dummy synchronization byte (10101010);
• one address byte – in case there are more receivers(or transmitters);
• one data byte;
• and checksum which is actually a sum of address and data(address+data).
Why did I use a dummy byte at the beginning of package. Simply I noticed, that when transmitter doesn't transmit any data – receiver catches various noises that come from power supply or other sources because receiver likes adjust its input gain depending on input signal level. First byte tunes receiver to accept normal signal after then address byte, data and checksum can be read more reliably. Probably with different transmission modules you may exclude this dummy byte.
Ttransmitter program for AVR Atmega8:
#include
#include
#ifndef F_CPU
//define cpu clock speed if not defined
#define F_CPU 8000000
#endif
//set desired baud rate
#define BAUDRATE 1200
//calculate UBRR value
#define UBRRVAL ((F_CPU/(BAUDRATE*16UL))-1)
//define receive parameters
#define SYNC 0XAA// synchro signal
#define RADDR 0x44
#define LEDON 0x11//switch led on command
#define LEDOFF 0x22//switch led off command
void USART_Init(void)
{
//Set baud rate
UBRRL=(uint8_t)UBRRVAL; //low byte
UBRRH=(UBRRVAL>>8); //high byte
//Set data frame format: asynchronous mode,no parity, 1 stop bit, 8 bit size
UCSRC=(1< (0< //Enable Transmitter and Receiver and Interrupt on receive complete
UCSRB=(1<}
void USART_vSendByte(uint8_t u8Data)
{
// Wait if a byte is being transmitted
while((UCSRA&(1< // Transmit data
UDR = u8Data;
}
void Send_Packet(uint8_t addr, uint8_t cmd)
{
USART_vSendByte(SYNC);//send synchro byte
USART_vSendByte(addr);//send receiver address
USART_vSendByte(cmd);//send increment command
USART_vSendByte((addr+cmd));//send checksum
}
void delayms(uint8_t t)//delay in ms
{
uint8_t i;
for(i=0;i _delay_ms(1);
}
int main(void)
{
USART_Init();
while(1)
{//endless transmission
//send command to switch led ON
Send_Packet(RADDR, LEDON);
delayms(100);
//send command to switch led ON
Send_Packet(RADDR, LEDOFF);
delayms(100);
}
return 0;
}
In my case I used UART 1200 baud rate. It may be increased or decreased depending on distance and environment. For longer distances lower baud rates works better as there is bigger probability for transmission errors. Maximum bit rate of transmitter is 8kbits/s what is about 2400 baud. But what works in theory usually do not work in practice. So 1200 baud is maximum what I could get working correctly.
Transmitter sends two commands (LEDON and LEDOFF) to receiver with 100ms gaps. Receiver recognizes these commands and switches LED on or off depending on received command. This way I can monitor if data transfer works correctly. If LED blink is periodical – then transmission goes without errors. If there is an error in received data then LED gives shorter blink.
Receiver program code:
#include
#include
#include
#ifndef F_CPU
//define cpu clock speed if not defined
#define F_CPU 4000000
#endif
//set desired baud rate
#define BAUDRATE 1200
//calculate UBRR value
#define UBRRVAL ((F_CPU/(BAUDRATE*16UL))-1)
//define receive parameters
#define SYNC 0XAA// synchro signal
#define RADDR 0x44
#define LEDON 0x11//LED on command
#define LEDOFF 0x22//LED off command
void USART_Init(void)
{
//Set baud rate
UBRRL=(uint8_t)UBRRVAL; //low byte
UBRRH=(UBRRVAL>>8); //high byte
//Set data frame format: asynchronous mode,no parity, 1 stop bit, 8 bit size
UCSRC=(1< (0< //Enable Transmitter and Receiver and Interrupt on receive complete
UCSRB=(1< //enable global interrupts
}
uint8_t USART_vReceiveByte(void)
{
// Wait until a byte has been received
while((UCSRA&(1< // Return received data
return UDR;
}
ISR(USART_RXC_vect)
{
//define variables
uint8_t raddress, data, chk;//transmitter address
//receive destination address
raddress=USART_vReceiveByte();
//receive data
data=USART_vReceiveByte();
//receive checksum
chk=USART_vReceiveByte();
//compare received checksum with calculated
if(chk==(raddress+data))//if match perform operations
{
//if transmitter address match
if(raddress==RADDR)
{
if(data==LEDON)
{
PORTC&=~(1<<0);//LED ON
}
else if(data==LEDOFF)
{
PORTC|=(1<<0);//LED OFF
}
else
{
//blink led as error
PORTC|=(1<<0);//LED OFF
_delay_ms(10);
PORTC&=~(1<<0);//LED ON
}
}
}
}
void Main_Init(void)
{
PORTC|=(1<<0);//LED OFF
DDRC=0X001;//define port C pin 0 as output;
//enable global interrupts
sei();
}
int main(void)
{
Main_Init();
USART_Init();
while(1)
{
}
//nothing here interrupts are working
return 0;
}
Receiver program receives all four bytes, then checks if checksum of received bytes is same as received checksum value. If checksum test passes then receiver addresses are compared and if signal is addressed to receiver it analyses data.
After all I have noticed that without antennas transmission is more erroneous even if modules are standing near by. Of course with all my power chords around the room I was getting lots of noises that receiver was catching between data transmissions.
►Introduction
Whenever a robotics hobbyist talk about making a robot, the first thing comes to his mind is making the robot move on the ground. And there are always two options in front of the designer whether to use a DC motor or a stepper motor. When it comes to speed, weight, size, cost... DC motors are always preffered over stepper motors. There are many things which you can do with your DC motor when interfaced with a microcontroller. For example you can control the speed of motor, you can control the direction of rotation, you can also do encoding of the rotation made by DC motor i.e. keeping track of how many turns are made by your motors etc. So you can see DC motors are no less than a stepper motor.
In this part of tutorial we will learn to interfacing a DC motor with a microcontroller. Usually H-bridge is preffered way of interfacing a DC motor. These days many IC manufacturers have H-bridge motor drivers available in the market like L293D is most used H-Bridge driver IC. H-bridge can also be made with the help of trasistors and MOSFETs etc. rather of being cheap, they only increase the size of the design board, which is somtimes not required so using a small 16 pin IC is preffered for this purpose.
►Working Theory of H-Bridge
The name "H-Bridge" is derived from the actual shape of the switching circuit which control the motoion of the motor. It is also known as "Full Bridge". Basically there are four switching elements in the H-Bridge as shown in the figure below.
As you can see in the figure above there are four switching elements named as "High side left", "High side right", "Low side right", "Low side left". When these switches are turned on in pairs motor changes its direction accordingly. Like, if we switch on High side left and Low side right then motor rotate in forward direction, as current flows from Power supply through the motor coil goes to ground via switch low side right. This is shown in the figure below.
Similarly, when you switch on low side left and high side right, the current flows in opposite direction and motor rotates in backward direction. This is the basic working of H-Bridge. We can also make a small truth table according to the switching of H-Bridge explained above.
Truth Table
High Left High Right Low Left Low Right Description
On Off Off On Motor runs clockwise
Off On On Off Motor runs anti-clockwise
On On Off Off Motor stops or decelerates
Off Off On On Motor stops or decelerates
As already said, H-bridge can be made with the help of trasistors as well as MOSFETs, the only thing is the power handling capacity of the circuit. If motors are needed to run with high current then lot of dissipation is there. So head sinks are needed to cool the circuit.
Now you might be thinkin why i did not discuss the cases like High side left on and Low side left on or high side right on and low side right on. Clearly seen in the diagra, you don't want to burn your power supply by shorting them. So that is why those combinations are not discussed in the truth table.
So we have seen that using simple switching elements we can make our own H-Bridge, or other option we have is using an IC based H-bridge driver. Both of them are discussed in the next section of the tutorial.
DC Motor interfacing with Microcontrollers tutorial: BJT Based H-Bridge for DC motors
►BJT H-Bridge
A simple H-bridge can be made with the help of Power BJTs like TIP31 and TIP32. An example and a working demo of this circuit is shown in the figure below.
►BJT H-Bridge Demo
DC Motor interfacing with Microcontrollers tutorial: L293D H-Bridge interfacing
►L293D Dual H-Bridge Motor Driver
L293D is a dual H-Bridge motor driver, So with one IC we can interface two DC motors which can be controlled in both clockwise and counter clockwise direction and if you have motor with fix direction of motion the you can make use of all the four I/Os to connect up to four DC motors. L293D has output current of 600mA and peak output current of 1.2A per channel. Moreover for protection of circuit from back EMF ouput diodes are included within the IC. The output supply (VCC2) has a wide range from 4.5V to 36V, which has made L293D a best choice for DC motor driver.
A simple schematic for interfacing a DC motor using L293D is shown below.
As you can see in the circuit, three pins are needed for interfacing a DC motor (A, B, Enable). If you want the o/p to be enabled completely then you can connect Enable to VCC and only 2 pins needed from controller to make the motor work.
As per the truth mentioned in the image above its fairly simple to program the microcontroller. Its also clear from the truth table of BJT circuit and L293D the programming will be same for both of them, just keeping in mind the allowed combinations of A and B. We will discuss about programming in C as well as assembly for running motor with the help of a microcontroller.
DC Motor interfacing with Microcontrollers tutorial: Programming Microcontroller
►Assembly programming
CODE:
L293D_A equ P2.0 ;L293D A - Positive of Motor
L293D_B equ P2.1 ;L293D B - Negative of Motor
L293D_E equ P2.2 ;L293D E - Enable pin of IC
org 0H
Main:
acall rotate_f ;Rotate motor forward
acall delay ;Let the motor rotate
acall break ;Stop the motor
acall delay ;Wait for some time
acall rotate_b ;Rotate motor backward
acall delay ;Let the motor rotate
acall break ;Stop the motor
acall delay ;Wait for some time
sjmp Main ;Do this in loop
rotate_f:
setb L293D_A ;Make Positive of motor 1
clr L293D_B ;Make negative of motor 0
setb L293D_E ;Enable to run the motor
ret ;Return from routine
rotate_b:
clr L293D_A ;Make positive of motor 0
setb L293D_B ;Make negative of motor 1
setb L293D_E ;Enable to run the motor
ret ;Return from routine
break:
clr L293D_A ;Make Positive of motor 0
clr L293D_B ;Make negative of motor 0
clr L293D_E ;Disable the o/p
ret ;Return from routine
delay: ;Some Delay
mov r7,#20H
back: mov r6,#FFH
back1: mov r5,#FFH
here: djnz r5, here
djnz r6, back1
djnz r7, back
ret
►C programming
CODE:
#include #define L293D_A P2_0 //Positive of motor
#define L293D_B P2_1 //Negative of motor
#define L293D_E P2_2 //Enable of L293D
// Function Prototypes
void rotate_f(void); //Forward run funtion
void rotate_b(void); //Backward run function
void breaks(void); //Motor stop function
void delay(void); //Some delay
void main(){ //Our main function
while(1){ //Infinite loop
rotate_f(); //Run forward
delay(); //Some delay
breaks(); //Stop
delay(); //Some delay
rotate_b(); //Run Backwards
delay(); //Some delay
breaks(); //Stop
delay(); //Some delay
} //Do this infinitely
}
void rotate_f(){
L293D_A = 1; //Make positive of motor 1
L293D_B = 0; //Make negative of motor 0
L293D_E = 1; //Enable L293D
}
void rotate_b(){
L293D_A = 0; //Make positive of motor 0
L293D_B = 1; //Make negative of motor 1
L293D_E = 1; //Enable L293D
}
void breaks(){
L293D_A = 0; //Make positive of motor 0
L293D_B = 0; //Make negative of motor 0
L293D_E = 0; //Disable L293D
}
void delay(){ //Some delay...
unsigned char i,j,k;
for(i=0;i<0x20;i++) j="0;j<255;j++)" k="0;k<255;k++);">