Friday, March 12, 2021

PIC16F887 ADC servomotor rotation MikroC

Servo Motor

Servo motor is a type of motor that rotate to specific degree assigned by a controller. Some motor rotates within 180 degree, while others rotate up to 360 degree.

PIC16F887 ADC servomotor rotation MikroC
A sample of servo motor from Ali Express
This is a high torque motor that could handle some heavy load especially robot arm. It has three wires - two for supply voltage while the remaining one is control signal.



Supply voltage is typically a +5V DC supply from microcontroller board. Its  control signal is a TTL type logic level with a frequency of about 50Hz. Duty time of control signal is between 1.5ms to 2ms that rotate its angle between 0 and 180 degrees.

Microcontroller Interfacing and Programming

Controller needs to generate Pulse Width Modulation (PWM) signal with a frequency around 50Hz, with a variation of high time between 1.5ms to 2ms to rotate this motor. Without using PWM module of controller, programmer can create a software PWM routine instead. However this method has a timing latency.

PIC16F887 ADC servomotor rotation MikroC
Simulation of this program

A POT connects to AN0 of PIC16F887 that's channel 0 of ADC module. Controller reads and converts this ADC value into timing value of output PWM signal generates a pin RD0. This pin controls the angle of rotation of servo motor.

MikroC Program:

  1. #define Servo PORTD.RD0
  2. #define Max_Degree 2000
  3. unsigned ADC_Value;
  4. unsigned Servo_Value;
  5.  
  6. void main() {
  7. int i,j;
  8. PORTD=0x00;
  9. PORTA=0x00;
  10. TRISA=0x01;
  11. ANSEL=0x01;
  12. TRISD=0x00;
  13. OSCCON=0x70;
  14. ADC_Init();
  15. while(1) {
  16. ADC_Value=ADC_Get_Sample(0);
  17. Servo_Value=ADC_Value/4;
  18. Servo=1;
  19. for(i=0;i<Servo_Value;i++) {
  20.  
  21. delay_us(1);
  22. }
  23. Servo=0;
  24. for(j=0;j<20000-Servo_Value;j++) {
  25.  
  26. delay_us(1);
  27. }
  28. delay_ms(5);
  29. }
  30. }

Click here to download this example from GitHub.



Thursday, March 11, 2021

A DC +50V DVM using ADC of PIC16F887 MikroC

Input signal to ADC channel of a microcontroller is other than DC voltage source. It typically range from 0 to 5V DC, as a conventional microcontroller, and voltage reference of ADC module are around +5V. Measuring input voltage within this range is straight forward using a calculation of ADC result and its step voltage size.

A DC +50V DVM using ADC of PIC16F887 MikroC
A DC +50V DVM using ADC of PIC16F887 MikroC - Program sample
Embedded controller is able to measure input DC voltage exceeding this range - for example measuring an input voltage of +50V DC. From electric circuit theory, voltage divider circuit divides input voltage source to lower output using two resistors.



Reference circuit from Wikipedia

Dividing factor depends on value of these two resistor that we can not give its detail and formula here. Using this method we can design a simple digital volt meter (DVM) with a maximum range of +50V DC.

In this example we select Z1 = 100kOhm and Z2 = 10kOhm. This circuit gives an output dividing factor of 0.09 at Vout. So whenever input voltage Vin = 50V then output voltage 50V * 0.09 that is around 5V, which is the maximum input voltage to ADC input channel.

A DC +50V DVM using ADC of PIC16F887 MikroC
Circuit Diagram

In this program timer0 is used to schedule ADC reading before it's converted to actual DC input voltage. Using its 8MHz internal oscillator source, timer0 interrupt creates a timer tick for scheduling ADC reading. Whenever the total tick equal to 30 it's a one second timing. Hence ADC reading is activated for every 30 timer0 tick (one second).

However multiplexing display doesn't use this timer tick due total lines of C source code.

MikroC source code:

  1. #define STEP_SIZE 0.0048
  2. #define ONE_SECOND 30
  3. #define RATE 3
  4. #define DIGIT1 PORTA.RA4
  5. #define DIGIT2 PORTA.RA5
  6. #define DIGIT3 PORTA.RA6
  7. #define DIGIT4 PORTA.RA7
  8.  
  9. unsigned ADC_Value,V_Measure;
  10. float Voltage;
  11. char int_count;
  12. char LED[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
  13. bit ADC_RUN;
  14.  
  15. void interrupt() {
  16. if(INTCON.T0IF) {
  17. int_count++;
  18. if(int_count==ONE_SECOND)
  19. { int_count=0; ADC_RUN=1; }
  20. }
  21. INTCON.T0IF=0;
  22. }
  23.  
  24. void PORT_SETUP() {
  25. PORTA=0x00;
  26. PORTB=0x00;
  27. TRISA=0x01; // RA0 IS ANALOG IN PUT
  28. TRISB=0x00; // PORTB is OUTPUT
  29. ANSEL=0x01; // SELECT AN0
  30. ANSELH=0x00; // OTHERS ARE DIGITAL IO
  31. OSCCON|=0x07; // SELECT 8MHz INT RC
  32. }
  33.  
  34. void Timer0_Setup(){
  35. OPTION_REG.T0CS=0; // SELECT FOSC/4
  36. OPTION_REG.PSA=0; // SELECT TIMER0 PRESCALER
  37. OPTION_REG|=0x07; // SELECT 1:256 PRESCALER
  38. }
  39.  
  40. void interrupt_setup() {
  41. INTCON.GIE=1;
  42. INTCON.T0IE=1;
  43. INTCON.T0IF=0;
  44. }
  45.  
  46. void Read_Temp () {
  47. if(ADC_RUN=1) {
  48. ADC_Value=ADC_Get_Sample(0); // READ AN0
  49. delay_ms(10);
  50. Voltage=ADC_Value*STEP_SIZE; // Convert to Decimal [Volt]
  51. }
  52. ADC_RUN=0;
  53. }
  54.  
  55. void SSD() {
  56. V_Measure=Voltage*10/0.090; // convert Voltage to integer
  57.  
  58. PORTB=LED[V_Measure/100];
  59. DIGIT1=1;
  60. delay_ms(RATE);
  61. PORTA=0x00;
  62.  
  63. PORTB=LED[(V_Measure%100)/10]|0x80;
  64. DIGIT2=1;
  65. delay_ms(RATE);
  66. PORTA=0x00;
  67.  
  68. PORTB=LED[V_Measure%10];
  69. DIGIT3=1;
  70. delay_ms(RATE);
  71. PORTA=0x00;
  72.  
  73. PORTB=0x62;
  74. DIGIT4=1;
  75. delay_ms(RATE);
  76. PORTA=0x00;
  77. }
  78.  
  79. void main() {
  80. ADC_Value=0;
  81. int_count=0;
  82. ADC_RUN=0;
  83. PORT_SETUP();
  84. ADC_Init();
  85. Timer0_Setup();
  86. Interrupt_Setup();
  87. while(1) {
  88. Read_Temp();
  89. SSD();
  90. }
  91. }
 
Click here to download this example program.

PIC16F887 ADC interfaces to LM35 thermometer

 Introduction LM35

LM35 is thermometer that converter surrounding temperature to analog voltage. Its analog voltage voltage is proportional to temperature that is 10mV per degree Celsius. It's supplied from a DC voltage source ranging from 4 to 30V. Conversion temperature is between -55 to 150 degree Celsius. 

PIC16F887 ADC interfaces to LM35 thermometer
Sample of this example program
 

Dual-In-Line Package of TO-92 is very popular for hobbyist prototyping of this kind of sensor. It's a three-pin transistor-like electronics device. These three pins are VDD, VOUT, and GND.

PIC16F887 ADC interfaces to LM35 thermometer
LM35DZ TO-92 transistor-like package

 From electronics component store this device costs below one USD.

Interfacing and Programming using MikroC

Using ADC module inside PIC16F887, temperature reading could be done easily and precise due to 10-bit resolution inside ADC module. Floating point calculation in program C allow result acquisition calculated within a line of C code.

PIC16F887 ADC interfaces to LM35 thermometer
Circuit Diagram
In this programming example, AN0 of PIC16F887 reads voltage value that represent temperature data. Conversion temperature in only positive since voltage reference of ADC here set to positive rail only.

Temperature data will show on multiplexed display driven by PortB. Device supplied from stabilized 5V DC voltage with 8MHz internal oscillator.



MikroC source code:

  1. #define STEP_SIZE 0.0048
  2. #define ONE_SECOND 30
  3. #define Volt_Per_Celcius 0.01
  4. #define RATE 1
  5. #define DIGIT1 PORTA.RA4
  6. #define DIGIT2 PORTA.RA5
  7. #define DIGIT3 PORTA.RA6
  8. #define DIGIT4 PORTA.RA7
  9.  
  10. unsigned ADC_Value;
  11. float Voltage,temp;
  12. char int_count,Temp_Data;
  13. char LED[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
  14. bit ADC_RUN;
  15.  
  16. void interrupt() {
  17. if(INTCON.T0IF) {
  18. int_count++;
  19. if(int_count==ONE_SECOND)
  20. { int_count=0; ADC_RUN=1; }
  21. }
  22. INTCON.T0IF=0;
  23. }
  24.  
  25. void PORT_SETUP() {
  26. PORTA=0x00;
  27. PORTB=0x00;
  28. TRISA=0x01; // RA0 IS ANALOG IN PUT
  29. TRISB=0x00; // PORTB is OUTPUT
  30. ANSEL=0x01; // SELECT AN0
  31. ANSELH=0x00; // OTHERS ARE DIGITAL IO
  32. OSCCON|=0x07; // SELECT 8MHz INT RC
  33. }
  34.  
  35. void Timer0_Setup(){
  36. OPTION_REG.T0CS=0; // SELECT FOSC/4
  37. OPTION_REG.PSA=0; // SELECT TIMER0 PRESCALER
  38. OPTION_REG|=0x07; // SELECT 1:256 PRESCALER
  39. }
  40.  
  41. void interrupt_setup() {
  42. INTCON.GIE=1;
  43. INTCON.T0IE=1;
  44. INTCON.T0IF=0;
  45. }
  46.  
  47. void Read_Temp () {
  48. if(ADC_RUN=1) {
  49. ADC_Value=ADC_Get_Sample(0); // READ AN0
  50. delay_ms(10);
  51. Voltage=ADC_Value*STEP_SIZE; // Convert to Decimal [Volt]
  52. }
  53. ADC_RUN=0;
  54. }
  55.  
  56. void SSD() {
  57. Temp_Data=Voltage/Volt_Per_Celcius; // convert Voltage to integer
  58.  
  59. PORTB=LED[Temp_Data/10]; //10's
  60. DIGIT1=1;
  61. delay_ms(RATE);
  62. PORTA=0x00;
  63.  
  64. PORTB=LED[Temp_Data%10]; // 1's
  65. DIGIT2=1;
  66. delay_ms(RATE);
  67. PORTA=0x00;
  68.  
  69. PORTB=0x63; // o
  70. DIGIT3=1;
  71. delay_ms(RATE);
  72. PORTA=0x00;
  73.  
  74. PORTB=0x39; // C
  75. DIGIT4=1;
  76. delay_ms(RATE);
  77. PORTA=0x00;
  78. }
  79.  
  80. void main() {
  81. ADC_Value=0;
  82. int_count=0;
  83. ADC_RUN=0;
  84. PORT_SETUP();
  85. ADC_Init();
  86. Timer0_Setup();
  87. Interrupt_Setup();
  88. while(1) {
  89. Read_Temp();
  90. SSD();
  91. }
  92. }

Timer0 is added to this example program. It's used for creating timer ticks that schedule ADC reading, and activating each digit of multiplexing display.

Click here to download this example.



Labels

ADC (10) Analog (14) Arduino (12) Atmega16 (19) Audio (2) AVR (20) Charger (1) Cortex-M0 (1) Counter (10) CPLD (25) Digital I/O (22) Display (34) EEPROM (2) Environment Sensor (1) esp8266 (2) Experiment Board (10) I2C (4) Interrupt (7) LCD (1) LDmicro (29) measurement and instrumentation (7) Microchip Studio (3) MikroC (1) One-Shot (3) OpAmp (1) PCB (31) PIC16 Microcontrollers (16) PIC16F877A (2) PIC16F887 MikroC (22) PLC (35) PWM (11) Regulator (1) RTC (2) Sensor (8) Shift Registers (5) SPI (5) Timer (34) UART (2) ultra-sonic sensor (1) USB (1) VHDL (21) xc8 (1) XC95108 (9) XC9536 (15) XC9572 (1) Xilinx (23) Xilinx ISE (22)