Monday, June 29, 2020

Using ADC and Timer/Counter 0 PWM of ATMega32 to rotate a DC servo motor

DC Servo Motor

A typical DC servo motor could rotate using a controlling pulse with a period of 50 Hz (20 milli seconds period). The duty cycle or high time is between 1 milli second to 2 milli seconds, with the corresponding rotating angle between -90 to +90 degree (180 degree in total).

Using ADC and Timer/Counter 0 PWM of ATMega32 to rotate a DC servo motor


Here, I use timer and counter 0 module of ATMega32 to create a PWM signal in phase correction mode. The frequency is 122 Hz regardless of the DC servo standard timing requirement. 

Using ADC and Timer/Counter 0 PWM of ATMega32 to rotate a DC servo motor
A sample of program

The clock fed to the CPU is 4 MHz. The timer/counter 0 prescaler is 1:64. The PWM frequency of phase correction mode is 4MHz/(64*510) which is 122.54 Hz. The period is 816 milli seconds.

For OCR0 step timing is (816 milli seconds)/256 is 31 micro seconds. To get a one milli second high time, OCR0 must be loaded 31. To get a two milli seconds high pulse, we must load OCR0 with 62 or 63. Hence OCR0 is varied between 31 to 63 to make the DC servo rotate at any angles.

The angle is get from the analog value from a POT fed to ADC7. The 10-bit (1024) ADC value is scaled to a decimal value of 32 as referred above.

Atmel Studio 7 C Coding

The AVR C source code is implemented as below.

#include <avr/io.h>
int main(void)
{
 unsigned int adcResult,adcOld=0;
 //PA0 or ADC0 as an analog input
 DDRA=0;
 //PWM OUT
 DDRB|=(1<<3);
 /*Turn on the ADC module
 ADC Clock divided by 128
 */
 ADCSRA|=(1<<ADEN)|0x07;
 ADMUX|=0x07;
 /*Set phase correct PWM mode with non
 inverting output
 */
 TCCR0|=(1<<COM01)|(1<<WGM00)|(1<<CS01)|(1<<CS00);
 //select 1:64 pre-scaler
 //TCCR0|=(1<<CS01)|(1<<CS00);
 while (1)
 {
  //Start the conversion
  ADCSRA|=(1<<ADSC);
  //Wait for the completion
  while((ADCSRA&(1<<ADSC))==1);
  
  adcResult=ADCL+(ADCH<<8);
  if(adcResult!=adcOld)
   OCR0=((adcResult*32)/1024)+31;
  adcOld=adcResult;
 }
}

Using ADC and Timer/Counter 0 PWM of ATMega32 to rotate a DC servo motor
Schematic diagram





Click here to download its source file.

Saturday, June 27, 2020

ATMega32 50 Volts DC Digital Voltmeter

Analog To Digital Converter (ADC) Module

The ADC module relates only with analog voltage value from any analog-output sensors or other analog circuits. Analog voltage value could be scaled to a smaller range value by using a two-resistor voltage divider circuit. For example a 50 V DC voltage could be scale to a range of lower than 5 V DC because the maximum analog reference voltage of ADC module of this device is +5 V DC.

ADC Scaling Circuit Using Voltage Divider Rule


For the voltage divider of two resistor, I do a calculation as follow.

ATMega32 50 V DC Digital VoltmeterATMega32 50 V DC Digital Voltmeter 

V (ADC) is the analog voltage fed to the ADC pin. It's the measuring voltage divided by 11, or 0.09 of the measuring voltage.

Using these two values of resistor, we could measure the analog voltage up to 50 V DC.

Program For Digital Voltmeter


ATMega32 50 V DC Digital Voltmeter
A sample of program. The voltage reading is 26.37 Volts.

Atmel Studio C source code. Click here to download source file.

 

Schematic diagram is here.

ATMega32 50 Volts DC Digital Voltmeter
The CPU clocks at 4 MHz. The display made up to five distinct single-digit SSDs.


Saturday, June 13, 2020

AT89C52 interfaces to a one wire DS18B20 digital thermometer

DS18X20 One-Wire Digital Temperature Sensor

DS1820 series is series of digital temperature sensor developed by Maxim Integrated. It uses one wire protocol. The master MCU accesses only one digital pin working in both direction. The slave ds18b20 has only three pins, two pins are supply voltage and one other is the data pin.

AT89C52 interfaces to a one wire DS18B20 digital thermometer


AT89C52 interfaces to a one wire DS18B20 digital thermometer
Two ds18b20 package I possess. 


AT89C52 interfaces to a one wire DS18B20 digital thermometer
DS18B20 TO-92 package. VDD and GND
are supply voltage. DQ is digital data pin.

The DS18B20 is one of its family. It could sample the temperature data between -55 to +125 degree Celsius.
The physical packages are available in TO-92, SMD and a probe-type. 
The temperature data is made of two 8-bit wide register giving a 16-bit temperature data. But it contain five signed bits. Temperature data has a 7-bit decimal and 4-bit fraction numbers.

AT89C52 interfaces to a one wire DS18B20 digital thermometer
S is signed indication

For full technical specification I can not show the full detail here. We can see the full specification from the datasheet. For programming example, we can get it from the application note done by the manufacturer. 

We can use multiple one wire devices on a single pin. Each device is identified by its 64-bit ROM ID.
Typically we need a pull-up resistor with a resistance between 4.7 k to 10 k Ohm depend on the data rate.

Programming in MikroC

MikroC is also available for 8051 devices family. It contains an extensive software and hardware libraries.
One wire library supports both ds18b20 and ds18s20. In MikroC it's called oneWire library. It contains some functions:
  • Ow_Reset
  • Ow_Read
  • Ow_Write
We need these three functions to access to the one wire devices.
In this example, I use AT89C52 to read the temperature data from a ds18b20 and display it to the multiplexed SSD.

AT89C52 interfaces to a one wire DS18B20 digital thermometer
AT89C52 CPU clocks at 24 MHz. Display is connected to P2 and P3. A single ds18b20
is connected to P1.2.

MikroC source code:


AT89C52 interfaces to a one wire DS18B20 digital thermometer
A negative temperature reading of -12.8 degree Celsius.


Click here to download this example.

Tuesday, June 9, 2020

AT89C52 interfaces to a 16x2 character LCD

Character LCD With HD44780 LCD Controller

A character LCD has been a popular display device for many decades. Currently, there are a dozen of modern display devices in the market. Most display device have a built-in LCD controller and driver. The Hitachi HD44780 is an industrial standard character LCD controller in use for many decades. However there are many alternative controller IC compatible with this device today.

AT89C52 interfaces to a 16x2 character LCD
A sample of 16x2 LCD with HD44780 compatible controller.
AT89C52 interfaces to a 16x2 character LCD
Pin diagram

With a high level programming language, programming this device could make from scratch. MikroC is popular C compiler targeting many different microcontrollers. It has a lot of built-in libraries comes with the compiler. Libstock is a supporting website contain many shared libraries made by many developers.

In this example, I use AT89C52 microcontroller from Atmel. It's a non-ISP flash microcontroller. But we can test the program of this device in simulator.

For this LCD module, there are 16 pins connection including the back LED. VSS and VDD are supply voltage pins, typically 5 V DC. RS (register select) pin use for selecting between LCD command and display data register. RW (read/write) use for reading and writing between the LCD and the MCU. Typically it's wired to ground because we just only write to LCD for displaying texts. E (enable) used for latching the 8-bit data to the LCD controller. A and K are back LED pins.

We don't need to explain more about technical details because we gonna use the high level programming language with a ready-to-use LCD library.

MikroC LCD Library For HD44780

In MikroC there are some related LCD function we gonna use here.
  1. Lcd_Init() this function initialize the LCD operation with 4-bit mode
  2. Lcd_Cmd() this function write the command to LCD such as clearing the display, moving cursor and so on.
  3. Lcd_Out() write the string of characters to the LCD at any position.
Before we can use these functions, the LCD pin connection declaration must be done first. For more details, please see the library function help file comes with the compiler.

AT89C52 interfaces to a 16x2 character LCD
AT89C52 clocks at 24 MHz. LCD connects to P3 using 4-bit data mode.

MikroC source code.

/*Select the control pins*/
sbit LCD_RS at P3_0_bit;
sbit LCD_EN at P3_1_bit;
/*Select the 4-bit data pins*/
sbit LCD_D4 at P3_4_bit;
sbit LCD_D5 at P3_5_bit;
sbit LCD_D6 at P3_6_bit;
sbit LCD_D7 at P3_7_bit;
void main(){
  long seconds=0;
  
  /*LCD inititializing*/
  Lcd_Init();
  /*Cleaning up display data*/
  Lcd_Cmd(_LCD_CLEAR);
  /*Turning Off The Cursor*/
  Lcd_Cmd(_LCD_CURSOR_OFF);
  /*Starting the texts*/
  Lcd_Out(1,3,"HELLO AT89C52");
  Lcd_Out(2,2,"MikroC For 8051");
  Delay_ms(2000);
  /*Erasing all Texts*/
  Lcd_Cmd(_LCD_CLEAR);
  while(1);
}

AT89C52 interfaces to a 16x2 character LCD
A running program shows a displaying texts before the MCU clear them.

Click here to download source file of this example.

We can use SN74HC595N shift registers chip to drive this character LCD in 4-bit mode. This chip converts from serial data that use SPI interface from microcontroller to parallel output. Parallel output data will drive the character LCD. So microcontroller uses only 3 pins to send serial data to serial character LCD module.

Monday, June 8, 2020

Using ADC of ATMega32 to adjust PWM duty cycle

In this module we have discuss about using ADC with some typical applications. Using a POT we can adjust the analog value fed to the ADC input pin manually and linearly. With this advantage we can use the ADC value to adjust the duty cycle of PWM signal.

In this example, I use ADC to vary the PWM duty cycle between 0 to 100%. The ADC value is scaled from 1024 to 100 to fit the PWM timing. PWM signal is created by timer 0 interrupt. Each interrupt occurs for every 10 micro seconds.

Using ADC of ATMega32 to adjust PWM duty cycle

Schematic diagram

Source code:

  1. #include <avr/io.h>
  2. #include "avr/interrupt.h"
  3. unsigned char cnt=0;
  4. void speedControl(unsigned int speed){
  5. float _dutyCycle;
  6. unsigned int dutyCycle;
  7. _dutyCycle=speed*(100.0/1024);
  8. //dutyCycle=20;
  9. dutyCycle=10+(int)_dutyCycle;
  10. if(cnt<dutyCycle) PORTD|=(1<<0);
  11. if(cnt>=dutyCycle) PORTD&=~(1<<0);
  12. if(cnt>=100) cnt=0;
  13. }
  14. int main(void)
  15. { unsigned int adcResult;
  16. //PortD as output
  17. DDRD=0xFF;
  18. //PA0 or ADC0 as an analog input
  19. DDRA=0;
  20. //Set 1:8 pre-scaler
  21. TCCR0=0x02;
  22. //Clear overflow flag
  23. TIFR=0x01;
  24. //Enable Timer 0 interrupt
  25. TIMSK=0x01;
  26. //set global interrupt
  27. sei();
  28. //Turn on the ADC module
  29. ADCSRA|=(1<<ADEN);
  30. /*Select ADC7*/
  31. ADMUX|=0x07;
  32. while (1)
  33. {
  34. //Start the conversion
  35. ADCSRA|=(1<<ADSC);
  36. //Wait for the completion
  37. while((ADCSRA&(1<<ADSC))==1); //Read the result
  38. adcResult=ADCL+(ADCH<<8);
  39. speedControl(adcResult);
  40. }
  41. }
  42. ISR(TIMER0_OVF_vect){
  43. //Load -5 to make 10 uS interrupt time
  44. TCNT0=-5;
  45. cnt+=1;
  46. TIFR=0x01;
  47. }
  48.  


Click here to download its source file. Back to main tutorial page ATMega32 tutorials in C with Atmel Studio 7.

Sunday, June 7, 2020

Temperature reading from LM35 with ADC module of ATMega32

In this ADC module, we have an easy example of interfacing with device ADC. LM35 is analog temperature sensor capable of measuring the temperature between -55 to 150 degree Celsius. It outputs an analog voltage value that is 10 mV per degree Celsius proportionally. For more information please see this post.

Reading an analog temperature data with ADC module of ATMega32
A sample picture and pin diagram of LM35

In this example the system could only read the positive temperature value. Because I have some difficulty of working with negative voltage reading at this time.

Reading an analog temperature data with ADC module of ATMega32
LM35 connects to ADC0. There is no negative temperature reading here.

Source code:

#include <avr/io.h>
#define  F_CPU 4000000UL
#include <util/delay.h>
int main(void)
{ float voltage;
 float temperature;
 int _temperature;
 char ssd[16]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,
 0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
 //PortC as output
 DDRC=0xFF;
 //PortD as output
 DDRD=0xFF;
 //PA0 or ADC0 as an analog input
 DDRA=0;
 //Turn on the ADC module
 ADCSRA|=(1<<ADEN);
 while (1)
 {
  //Start the conversion
  ADCSRA|=(1<<ADSC);
  //Wait for the completion
  while((ADCSRA&(1<<ADSC))==1);
  /*Convert ADC to voltage*/
  voltage=(ADCL+(ADCH<<8))*5.0/1024;
  /*Convert to temperature*/
  temperature=voltage*100;
  /*make dot point*/
  temperature*=10;
  _temperature=(int)temperature;
  /*Displaying the Data*/
  PORTD=0x00;
  PORTC=ssd[_temperature/1000];
  if(_temperature>=1000) PORTD=0x01;
  _delay_ms(10);
  PORTD=0x00;
  PORTC=ssd[(_temperature%1000)/100];
  PORTD=0x02;
  _delay_ms(10);
  PORTD=0x00;
  PORTC=ssd[(_temperature%100)/10]|0x80;
  PORTD=0x04;
  _delay_ms(10);
  PORTD=0x00;
  PORTC=ssd[_temperature%10];
  PORTD=0x08;
  _delay_ms(10);
   }
}

Back to main tutorial page ATMega32 tutorials in C with Atmel Studio 7.

Reading an analog temperature data from LM35 with ADC module of ATMega32



Click here to download its source file.


Saturday, June 6, 2020

Making a simple +5 V voltmeter with ATMega32 ADC module

In the previous post, we have introduce about the ADC module of ATMega32. Actually the maximum reference voltage of the ADC is +5 V in usual. From this concept we can measure an input analog voltage input to any ADC channel at +5 V full scale reading.

The reading ADC value in the single ended conversion could be obtained from:
Making a simple +5 V voltmeter with ATMega32 ADC module
Reference voltage VREF is normally +5 V. Input voltage must not exceed +5 V.

To calculate the voltage, we can obtain it from:
Making a simple +5 V voltmeter with ATMega32 ADC module 

In this example, I use ADC0 to read an analog input voltage fed from a POT. The POT varies an analog output voltage from 0 V to +5 V DC. The MCU displays the reading result of the voltage from 0.0 V to 5.0 V.

Making a simple +5 V voltmeter with ATMega32 ADC module
ADC0 read the input analog voltage. PortC and PortD drive a two-digit
SSD. The voltage reading is from 0.0 V to 5.0 V.

Source code is here:

#include <avr/io.h>
#define  F_CPU 4000000UL
#include <util/delay.h>
int main(void)
{ float voltage;
 char _voltage;
 char ssd[16]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,
  0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
    //PortC as output
    DDRC=0xFF;
    //PortD as output
    DDRD=0xFF;
    //PA0 or ADC0 as an analog input
    DDRA=0;
    //Turn on the ADC module
    ADCSRA|=(1<<ADEN);
    while (1)
    {
     //Start the conversion
     ADCSRA|=(1<<ADSC);
     //Wait for the completion
     while((ADCSRA&(1<<ADSC))==1);
     /*Convert ADC to voltage*/
     voltage=(ADCL+(ADCH<<8))*5.0/1024;
  voltage*=10;
  /*convert float to SSD data*/
  _voltage=(char)voltage;
  /*Displaying the Data*/
  PORTD=0x00;
  PORTC=ssd[_voltage/10]|0x80;
  PORTD=0x01;
  _delay_ms(10);
  PORTD=0x00;
  PORTC=ssd[_voltage%10];
  PORTD=0x02;
  _delay_ms(10);
    }
}

Making a simple +5 V voltmeter with ATMega32 ADC module
The ADC reading is 2.5 V analog voltage.

Back to main tutorial page ATMega32 tutorials in C with Atmel Studio 7.




Search This Blog

Labels

25AA010A (1) 8051 (7) 93AA46B (1) ADC (30) Analog Comparator (1) Arduino (15) ARM (6) AT89C52 (7) ATMega32 (56) AVR (57) CCS PICC (28) DAC (1) DHT11 (2) Display (105) Distance Sensor (3) DS18B20 (3) dsPIC (2) dsPIC30F1010 (2) EEPROM (5) Environment Sensor (4) esp8266 (1) I2C (29) Input/Output (67) Interrupt (19) Keil (5) Keypad (10) LCD (47) Master/Slave (1) MAX7221 (1) MCP23017 (5) MCP23S17 (4) Meter (3) MikroC (2) Motor (15) MPLABX (71) Nokia 5110 LCD (3) OLED (2) One-Wire (6) Oscillator (8) PCB (6) PCD8544 (3) PCF8574 (5) PIC (107) PIC12F (2) PIC16F628A (2) PIC16F630 (1) PIC16F716 (3) PIC16F818 (10) PIC16F818/819 (2) PIC16F84A (15) PIC16F876A (1) PIC16F877A (9) PIC16F88 (1) PIC16F887 (60) PIC18 (19) PIC18F1220 (4) PIC18F2550 (3) PIC18F4550 (12) PWM (11) RTC (8) Sensor (10) SH1106 (1) Shift Register (11) Shift Registers (3) SPI (24) STM32 (6) STM32 Blue Pill (6) STM32CubeIDE (6) STM32F103C8T6 (6) SysTick (3) temperature sensor (11) Thermometer (21) Timer/Counter (31) TM1637 (2) UART (7) Ultrasonic (4) Voltmeter (7) WDT (1) XC16 (2) XC8 (94)