pia-468x60

pia-728x90

Wednesday, April 28, 2021

PIC16F887 PWM Programming in MikroC

Introduction

Pulse Width Modulation (PWM) generate an analog output waveform from microcontroller output pin. Enhanced Capture/Compare/PWM (CCP1) peripheral of PIC16F887 is able to generate analog output signal.

PIC16F887 PWM Programming in MikroC
Block diagram of PWM module of CCP1
There are some related registers of SFR to configure in program to make PWM work. However in MikroC, there is a PWM library for this peripheral. In this post we will make this module work first without making any complication with SFR.

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.

Labels