Learn To Write Code For 8051, Arduino, AVR, dsPIC, PIC, STM32 ARM Microcontroller, etc.
Coding Embedded Controller With C/C++.
Printed Circuit Board (PCB) Project For Electronics Hobbyists.
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).
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.
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;
}
}
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.
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
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.
The CPU clocks at 4 MHz. The display made up to five distinct single-digit SSDs.
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.
Two ds18b20 package I possess.
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.
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 CPU clocks at 24 MHz. Display is connected to P2 and P3. A single ds18b20
is connected to P1.2.
MikroC source code:
A negative temperature reading of -12.8 degree Celsius.
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.
A sample of 16x2 LCD with HD44780 compatible controller.
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.
Lcd_Init() this function initialize the LCD operation with 4-bit mode
Lcd_Cmd() this function write the command to LCD such as clearing the display, moving cursor and so on.
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 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);
}
A running program shows a displaying texts before the MCU clear them.
Click here to download source file of this example.
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.
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.
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.
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);
}
}
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:
Reference voltage VREF is normally +5 V. Input voltage must not exceed +5 V.
To calculate the voltage, we can obtain it from:
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.
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);
}
}