Professional Documents
Culture Documents
Microcontroller
Hi Friends,
Here Im discussing DC motor control using the PWM counters of AVR ATmega8 microcontroller. I had used a DC
motor from an old personal stereo cassette player. The circuit provides speed and direction control of the motor. The
PWM waveforms are used for driving the MOSFET H-bridge as shown in the schematic:
At a time only one of the two PWM channel is active, driving only two MOSFETS (either Q1-Q4 or Q3-Q2). Other two
MOSFETs remain OFF. Whenever the Direction Control switch is toggled, the PWM channel is also changed, driving
the alternative pair of MOSFET, which changes the direction of current flow through motor, resulting in the direction
change in rotation of motor shaft.
Code:
//********************************************************
// *********** PWM DC MOTOR CONTROL *************
//********************************************************
//Controller : ATmega8 (1MHz internal Crystal)
//Compiler
: ICCAVR
//Author
: CC Dharmani, Chennai(India)
//Date
: Nov 2008
//********************************************************
#include <iom8v.h>
#include <macros.h>
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
STOP_MOTOR
START_MOTOR
set_FORWARD
set_REVERSE
TCCR1B
TCCR1B
TCCR1A
TCCR1A
=
=
=
=
//defining macros for setting minimum and maximum PWM counter values
//and step-size for controlling the voltage applied to MOSFETs base
#define COUNTER_LOWER_LIMIT 0x0090
#define COUNTER_UPPER_LIMIT 0x00f8
#define STEP_SIZE 0x0008
void port_init(void)
{
PORTB = 0x00;
DDRB = 0x06; //PWM pins OC1A & OC1B defined as outputs
PORTC = 0x00;
DDRC = 0x00;
PORTD = 0xE0; //internal pull-up enabled for three pins connected to switches
DDRD = 0x00;
}
//TIMER1 initialize - prescale:1
//PWM Frequency: 1KHz
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1H = 0xFC; //setup
TCNT1L = 0x18;
OCR1A = COUNTER_LOWER_LIMIT;
OCR1B = COUNTER_LOWER_LIMIT;
ICR1H = 0x03;
ICR1L = 0xE8;
TCCR1A = 0x81; //set forward; OC1A connected, OC1B disconnected
TCCR1B = 0x09; //start Timer
}
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
timer1_init();
MCUCR = 0x00;
GICR = 0x00;
TIMSK = 0x00; //timer interrupt sources
SEI(); //re-enable interrupts
//all peripherals are now initialized
}
//***** FUNCTION FOR SOFTWARE DELAY OF 1 mSEC (appx.) *******
void delay_ms(int miliSec) //for 1 Mhz crystal
{
int i,j;
for(i=0;i<miliSec;i++)
for(j=0;j<100;j++)
{
asm("nop");
asm("nop");
}
}
//************************ main ***************************
void main(void)
{
unsigned int counter = COUNTER_LOWER_LIMIT;
unsigned char dir = 0, dir1 = 0;
init_devices();
while(1)
{
CHECK_PB:
while(increaseButton_OPEN && decreaseButton_OPEN)
{ //loop here until any push-button is pressed
if(DIRECTION_FORWARD) //check for Direction control switch status
dir = 0;
else
dir = 1;
if(dir != dir1) //chenge direction if switch position has changed
{
STOP_MOTOR;
delay_ms(500);
if(dir == 0)
set_FORWARD;
else
set_REVERSE;
START_MOTOR;
dir1 = dir;
}
}
if(increaseButton_PRESSED) //Speed-increase push-button is pressed
{
delay_ms(20); //key debouncing delay after key-pressed
if(increaseButton_OPEN) goto CHECK_PB;
while(increaseButton_PRESSED); //wait here till the push-button is kept pressed
delay_ms(20); //key debouncing delay after key released
if(counter >= COUNTER_UPPER_LIMIT) //if speed is already maximum, no action
counter = COUNTER_UPPER_LIMIT;
else
counter += STEP_SIZE; //increase speed by a fixed step
OCR1A = counter;
OCR1B = counter;
}
else //speed-decrease push-button is pressed
{
delay_ms(20); //key debouncing delay after key-pressed
if(decreaseButton_OPEN) goto CHECK_PB;
while(decreaseButton_PRESSED); //wait here till the push-button is kept pressed
delay_ms(20); //key debouncing delay after key released
if(counter <= COUNTER_LOWER_LIMIT) //if speed is already minimum, no action
counter = COUNTER_LOWER_LIMIT;
else
counter -= STEP_SIZE; //reduce speed by a fixed step
OCR1A = counter;
OCR1B = counter;
}
}
}
//****************************** END ***************************************
//********** CC Dharmani, www.dharmanitech.com ****************
Code:
//*****************************************************************
// **************** ADC_routines.h *********************
//*****************************************************************
#ifndef ADC_ROUTINES_H
#define ADC_ENABLE ADCSRA |= (1<<ADEN)
#define ADC_DISABLE ADCSRA &= 0x7F
#define ADC_START_CONVERSION ADCSRA |= (1<<ADSC)
void ADC_init(void);
int ADC_read(void);
float ADC_calculateTemp(int);
unsigned char* updateTempDisplay(float);
unsigned char* temporary(void);
void ADC_displayValue(void);
#endif
//*****************************************************************
// **************** ADC_routines.c *********************
//*****************************************************************
//Controller: ATmega32 (16 MHz)
//Compiler: ICCAVR
//Author: CC Dharmani, Chennai
//Date: Aug 2008
//*****************************************************************
#include
#include
#include
#include
<iom32v.h>
<macros.h>
"ADC_routines.h"
"LCD_routines.h"
the LCD
* Paramtr : None
* Return : None
***************************************************************************/
void ADC_displayValue(void)
{
int value;
float value1;
value = ADC_read();
value1 = ADC_calculateValue(value);
LCD_DisplayString(2,4,updateDisplay(value1)); //voltage display on 2nd row,
//4th column
}
//*****************************************************************
// **************** LCD_routines.c *********************
//*****************************************************************
#ifndef LCD_ROUTINES_H
// *** LCD Functions declaration *** //
void LCD_init(void);
void LCD_WriteCommand (unsigned char CMD);
void LCD_WriteData (unsigned char Data);
void
void
void
void
//********************************************************
// ************** LCD_routines.c ******************
//********************************************************
//Controller: ATmega32 (16 MHz)
//Compiler: ICCAVR
//Author: CC Dharmani, Chennai
//Date: Aug 2008
//********************************************************
#include <iom32v.h>
#include <macros.h>
#include "LCD_routines.h"
// *********************************
// *** Initialize the LCD driver ***
// *********************************
void LCD_init(void)
{
delay_ms(100); // wait for 100ms
LCD_WriteCommand
LCD_WriteCommand
LCD_WriteCommand
LCD_WriteCommand
(0x38);
(0x06);
(0x0f);
(0x01);
//
//
//
//
8 data lines
cursor setting
display ON
clear LCD memory
default: break;
}
}
// ********************************************************
// **** Function for delay of 1 msec (appx.) at 16Mhz *****
// ********************************************************
void delay_ms(int miliSec) //for 16 Mhz crystal
{
int i,j;
for(i=0;i<miliSec;i++)
for(j=0;j<1550;j++)
{
asm("nop");
asm("nop");
}
}
//********************************************************************
// ADC_main.h
//********************************************************************
#ifndef ADC_MAIN_H
#define KEY_PRESSED !(PINB & 0x02)
#define KEY_OPEN (PINB & 0x02)
void port_init(void);
void init_devices(void);
#endif
//********************************************************************
// ****** MAIN PROGRAM FOR TESTING ADC OF MEGA32 ADC_main.c******
//********************************************************************
//Controller: ATmega32 (Crystal: 16Mhz)
//Compiler: ICCAVR
//Author: CC Dharmani, Chennai
//Date: Aug 2008
//********************************************************************
#include
#include
#include
#include
#include
<iom32v.h>
<macros.h>
"ADC_main.h"
"LCD_routines.h"
"ADC_routines.h"
//port initialize
void port_init(void)
{
DDRA = 0x00;
PORTA = 0x00;
DDRB = 0x00;
PORTB = 0x02; //internal pull-up for push-button
DDRC = 0xFF;
PORTC = 0x00;
DDRD = 0xF0;
PORTD = 0x00;
}
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
ADC_init();
LCD_init();
MCUCR = 0x00;
TIMSK = 0x00; //timer interrupt sources
// SEI(); //re-enable interrupts
}
// MAIN FUNCTION
void main(void)
{
unsigned char channel = 0;
init_devices();
LCD_DisplayString_F(1,1,"ADC Testing.. ");
while(1)
{
LCD_DisplayString_F(2,1,"CH");
LCD_WriteData(channel | 0x30); //display channel number
START:
while(KEY_OPEN) //wait here till key is open
{
ADMUX &= 0xe0;
ADMUX |= channel; //select ADC channel
ADC_displayValue();
delay_ms(50);
}
delay_ms(20); //key debounce delay when key is pressed
if(KEY_OPEN)
goto START;
while(KEY_PRESSED); //wait here till key is pressed
delay_ms(20); //key debounce delay when key is released
channel++; //select next channel after key-press
if(channel == 8) //only channel-0 to channel-7 can be selected
channel = 0;
}
}
Make-Yourself ATmega32 Starter's Kit with LCD, I2C, SPI, RTC, ADC interfaces
Hi friends,
here is my home-made kit of ATmega32 microcontroller interfacing. The ATmega32 controller is rich with
features like onboard 32kB in-System programmable flash, 1 KB EEPROM, 2KB SRAM, 10bit ADC (8 channel),
SPI bus inteface, TWI (compatible with I2C bus) interface, an USART, analog comparator, etc.
That's why I've selected it to load my kit with all those features. This M32 card is having an LCD inteface with
contrast adjustment, an RS232 port for connecting with PC, a connector for 8 analog voltage inputs to measure
by ADC, a Real Time Clock IC DS1307 from maxim with battery back-up, four general purpose keys, two keys
for generating interrupts and an LED.
The circuit can be powered by an easily available 12v DC adapter. The voltage regulator IC 7805 used to convert
the input into regulated 5v supply.
See below the kit in powered on condition and the schematic.
The PCB is completely home-made, using the etching technique with the Ferric Chloride chemical. If you want to
know how to make a PCB yourself from your layout, visit following webpage, it's really helpful:
http://electrons.psychogenic.com/modules/arms/art/10/pcb_howto.php
The schematic and layout of the M32_card shown here are prepared using EAGLE. It's a single layer board for
making the home-preparation easy. Check out the bottom layer and the layouts in the pics below:
The software for the ATmega32 controller is written using imageCraft AVR compiler. The software contains code
for LCD interface, use of RTC and communication with PC with RS232 port. Using the Hyper terminal in
windows, the functionality of the kit can be checked, as I've mentioned in my previous post of RTC_EEPROM
interface with ATmega128.
Sown below are the pics of RTC circuit in test and related screen shot of the hyper terminal while interacting with
the M32_Card
The complete source code files including new addition of ADC (check out Here) can be downloaded in zip format
from AVRfreaks forum where I've posted them.
to me if you have any problem in downloading these files)
You can download the datasheets here:
ATmega32 DS1307 MAX232
If any one is interested in making this kit at home, write to me. I'll send u the shcematic and layout files with the
program.
Do write your comments, guys!!!
--------
UART FUNCTIONS
***********************************
Hi friends,
This document provides functions for using UART on AVR controllers for communication with PC RS232 port. Ive
tested these functions using ATmega32, with little changes it can be adapted to other atmega devices as well.
Code:
//****************************************************************
//**** UART ROUTINES *******************
//****************************************************************
//Controller: ATmega32 (16MHz Crystal)
//Compiler: ICCAVR
//Author: CC Dharmani, Chennai
//****************************************************************
//***************************************************
//Function to initialize UART
//***************************************************
//UART0 initialize
// desired baud rate: 19200
// actual: baud rate:19231 (0.2%)(at 16MHz crystal)
// char size: 8 bit
// parity: Disabled
void uart0_init(void)
{
UCSRB = 0x00; //disable while setting baud rate
UCSRA = 0x00;
UCSRC = BIT(URSEL) | 0x06;
UBRRL = 0x33; //set baud rate lo
UBRRH = 0x00; //set baud rate hi
UCSRB = 0x98;
}
//**************************************************
//Function to receive a single byte
//*************************************************
unsigned char receiveByte( void )
{
unsigned char data, status;
while(!(UCSRA & (1<<RXC))); // Wait for incomming data
status = UCSRA;
data = UDR;
return(data);
}
//***************************************************
//Function to transmit a single byte
//***************************************************
void transmitByte( unsigned char data )
{
while ( !(UCSRA & (1<<UDRE)) ); //Wait for empty transmit buffer
//***************************************************
//Function to transmit a string stored in Flash
//***************************************************
//***************************************************
//Function to transmit a string from RAM
//***************************************************
void transmitString(unsigned char* string)
{
while (*string)
transmitByte(*string++);
Code:
The code is given here. Please note that if you have bought a new ATmega32 IC then you have to disable the JTAG
interface which is multiplexed with the PORTC pins. JTAG can be disabled by changing the fuse values while
programming, refer to datasheet for further details. If JTAG is not disabled, the LCD will remain blank. Alternatively,
you can connect LCD with PORTA, and change the code accordingly to replace PORTC with PORTA.
After loading the code into microcontroller, the LCD will display a message Hi, welcome! Have a nice Day. When the
key is pressed the message will change to Atmega32 Board Starters kit. The messages will toggle between this two
whenever the pushbutton is pressed.
//********************************************************
void LCD_init(void);
void LCD_WriteCommand (unsigned char CMD);
void LCD_WriteData (unsigned char Data);
void LCD_DisplayString_F(char row, char column, const unsigned char *string);
void LCD_Cursor(char row, char column);
void delay_ms(int miliSec);
#include <iom32v.h>
#include <macros.h>
#include "LCD.h"
void port_init(void)
{
DDRA = 0x00;
PORTA = 0x00;
DDRB = 0x00;
PORTB = 0x00;
DDRC = 0xFF;
PORTC = 0x00;
DDRD = 0xF0;
PORTD = 0x00;
}
MCUCR = 0x00;
GICR = 0x00;
TIMSK = 0x00; //timer interrupt sources
}
init_devices();
while(1)
{
if(Change_Display != Change_Display1)
{
if(Change_Display==0)
{
LCD_DisplayString_F(1,1," Hi, Welcome! ");
LCD_DisplayString_F(2,1,"Have a nice Day");
}
else
{
LCD_DisplayString_F(1,1," ATmega32 Board ");
LCD_DisplayString_F(2,1," Starter's Kit ");
}
Change_Display1 = Change_Display;
}
CHECK_PB:
while(pushButton1_OPEN);// wait here until push
button1 is //pressed
delay_ms(20); // 20ms delay for key debouncing
// after key-pressed
}
}
//*********************************************************
//*********************** LCD Functions ***************
//*********************************************************
// *********************************
// *** Initialize the LCD driver ***
// *********************************
void LCD_init(void)
{
delay_ms(100); // wait for 100ms
LCD_WriteCommand (0x38); // 8 data lines
LCD_WriteCommand (0x06); // cursor setting
LCD_WriteCommand (0x0f); // display ON
LCD_WriteCommand (0x01); // clear LCD memory
delay_ms (10); // 10ms delay after clearing LCD
}
// **********************************************
// *** Write a command instruction to the LCD ***
// **********************************************
void LCD_WriteCommand (unsigned char Command)
{
asm("nop");
asm("nop");
DISABLE_LCD; // Disable LCD
delay_ms(1); // wait for 1ms
}
// *****************************************
// *** Write one byte of data to the LCD ***
// *****************************************
void LCD_WriteData (unsigned char Data)
{
SET_LCD_DATA; // Set LCD in data mode
asm("nop");
asm("nop");
// ************************************************************
// ***************************************************
// *** Position the LCD cursor at "row", "column". ***
// ***************************************************
void LCD_Cursor (char row, char column)
{
switch (row)
{
case 1: LCD_WriteCommand (0x80 + column - 1); break;
case 2: LCD_WriteCommand (0xc0 + column - 1); break;
default: break;
}
}
// ********************************************************
// **** Function for delay of 1 msec (appx.) at 16Mhz *****
// ********************************************************
void delay_ms(int miliSec) //for 16 Mhz crystal
{
int i,j;
for(i=0;i<miliSec;i++)
for(j=0;j<1550;j++)
{
asm("nop");
asm("nop");
}
}
Schematic:
Code:
//*****************************************************************
// ******** 4X4 MATRIX KEY-BOARD INTERFACING *******
//*****************************************************************
//Controller: ATmega32 (Crystal: 16 Mhz)
//Compiler: ImageCraft ICCAVR
//Author: CC Dharmani, Chennai (India)
//Date: Aug 2008
//********************************************************
#include <iom32v.h>
#include <macros.h>
// *** LCD Functions declaration *** //
void LCD_init(void);
void LCD_WriteCommand (unsigned char CMD);
void LCD_WriteData (unsigned char Data);
void LCD_DisplayString_F(char row, char column, const unsigned char *string);
void LCD_Cursor(char row, char column);
void delay_ms(int miliSec);
#define
#define
#define
#define
#define
#define
void port_init(void)
{
DDRA = 0x00;
PORTA = 0x00;
DDRB = 0x0f; //Key-board port, higer nibble - input, lower nibble - output
PORTB = 0xff; //pull-up enabled for higher nibble
DDRC = 0xff;
PORTC = 0x00;
DDRD = 0xf0;
PORTD = 0x00;
}
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
LCD_init();
MCUCR = 0x00;
TIMSK = 0x00; //timer interrupt sources
}
//****************** MAIN FUNCTION *******************
void main(void)
{
unsigned char upperNibble, keyCode, keyPressed, i;
init_devices();
LCD_DisplayString_F(1,1," WELCOME ");
LCD_WriteCommand(0xc0); //moving LCD cursor to second row
while(1)
{
upperNibble = 0xff;
for(i=0; i<4; i++)
{
delay_ms(1);
KB_PORT_OUT = ~(0x01 << i);
delay_ms(1); //delay for port o/p settling
upperNibble = KB_PORT_IN | 0x0f;
if (upperNibble != 0xff)
{
delay_ms(20); //key debouncing delay
upperNibble = KB_PORT_IN | 0x0f;
if(upperNibble == 0xff) goto OUT;
keyCode = (upperNibble & 0xf0) | (0x0f & ~(0x01 << i));
while (upperNibble != 0xff)
upperNibble = KB_PORT_IN | 0x0f;
delay_ms(20); //key debouncing delay
switch (keyCode) //generating key characetr to display on LCD
{
case (0xee): keyPressed = '0';
break;
case (0xed): keyPressed = '1';
break;
case (0xeb): keyPressed = '2';
break;
case (0xe7): keyPressed = '3';
break;
case (0xde): keyPressed = '4';
break;
case (0xdd): keyPressed = '5';
break;
case (0xdb): keyPressed = '6';
break;
case (0xd7): keyPressed = '7';
break;
case (0xbe): keyPressed = '8';
break;
case (0xbd): keyPressed = '9';
break;
case (0xbb): keyPressed = 'A';
break;
case (0xb7): keyPressed = 'B';
break;
case (0x7e): keyPressed = 'C';
break;
case (0x7d): keyPressed = 'D';
break;
case (0x7b): keyPressed = 'E';
break;
case (0x77): keyPressed = 'F';
break;
default : keyPressed = 'X';
}//end of switch
LCD_WriteData(keyPressed);
OUT:;
}//end
}//end
}//end
}//end
of
of
of
of
if
for
while(1)
main()
// **********************************************
// *** Write a command instruction to the LCD ***
// **********************************************
void LCD_WriteCommand (unsigned char Command)
{
SET_LCD_CMD; // Set LCD in command mode
PORTC = Command; // Load data to port
asm("nop");
}
}
BLINKING LED
***************************************
Hi friends, this is a beginners project of blinking an LED connected to AVR microcontroller ATmega32, as shown in
the schematic
Code:
Following code will make the Led blink every second (appx.) at 16MHz crystal. If you have bought new controller then
It will be set at internal 1MHz osc. (by default). So,if you dont change the fuse values to enable external crystal, the
LED will blink 16 times slower!!
//***************************************************
//************ BLINKING LED ***********************
//***************************************************
// Target : ATmega32
// Crystal: 16.000Mhz
// Compiler: ICCAVR
// Author: CC Dharmani, Chennai, India
//***************************************************
#include <iom32v.h>
#include <macros.h>
//----------------------------------------------void port_init(void)
{
PORTD = 0x00;
DDRD = 0x10;
}
{
asm("nop");
asm("nop");
}
}
MCUCR = 0x00;
GICR = 0x00;
TIMSK = 0x00; //timer interrupt sources
//SEI(); //re-enable interrupts
//all peripherals are now initialized
}
delay_ms(500);
PORTD &= ~0x10;
delay_ms(500);
}
}
//********************* END ***********************
Here is the same code written for AVR-GCC (winAVR) compiler:
//******* LED BLINKING PROGRAM *********
//Controller: ATmega32 (1Mhz or 16Mhz)
//Compiler: AVR-GCC (winAVR)
//Author: CC Dharmani, Chennai (INDIA)
//*************************************
//#define F_CPU 1000000UL
//use this if internal oscillator is used
#define F_CPU 16000000UL //use this when ext 16MHz crystal is used
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
void port_init(void)
{
PORTD = 0x00;
DDRD = 0x10;
}
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
cli(); //disable all interrupts
port_init();
MCUCR = 0x00;
GICR = 0x00;
TIMSK = 0x00; //timer interrupt sources
// sei(); //re-enable interrupts
//all peripherals are now initialized
}
int main()
{
init_devices();
while(1)
{
PORTD = 0x10;
_delay_ms(500);
PORTD = 0;
_delay_ms(500);
}
return(0);
}
//---------- END -------------