Hi,
You can try this idea. It will never go under 50% using 125 as a constant. Then divide your adcin by 2 this variable will be 0 to 127
Duty = 125 + adcin/2
Hi,
You can try this idea. It will never go under 50% using 125 as a constant. Then divide your adcin by 2 this variable will be 0 to 127
Duty = 125 + adcin/2
Last edited by mark_s; - 25th October 2015 at 23:39.
Yes, because you said you were using 8 bit pwm. You can change that to fit your needs.
On another note, I observed that with ADCIN the readings fluctuate quite a lot and I only want to change the motor speed if the value has 'really' changed (i.e. by me). I tried this code and while it yields a rock-solid value, it doesn't go to 0: the readings go from 1-255. Any ideas why?
Code:' PIC 16F1825 with a 10k pot attached to AN1 (the data sheet says this is the maximum impedance allowed) #DEFINE USE_LCD_FOR_DEBUG ; comment out for non-debug use ' Vdd -> pin 1 -> +5V ' RC4/Tx -> pin 6 -> EUSART transmit (LCD) ' RA1 -> pin 12 -> trim pot input ' Vss -> pin 14 -> GND DEFINE OSC 16 ; Set oscillator 16Mhz DEFINE ADC_BITS 8 ; Set number of bits in result DEFINE ADC_SAMPLEUS 50 ; Set sampling time in uS (was 5) DEFINE ADC_CLOCK 3 ; Set clock source (3=rc) DEFINE HSER_TXSTA 20h ; Set transmit status and control register DEFINE HSER_BAUD 2400 ; Set baud rate ' *************************************************************** ' Device Fuses ' *************************************************************** #CONFIG __config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF __config _CONFIG2, _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LVP_OFF #ENDCONFIG ' *************************************************************** ' Initialization ' *************************************************************** OSCCON = %01111000 ; 16MHz internal osc APFCON0.2 = 0 ; Tx on RC4 for LCD display APFCON0.7 = 0 ; Rx on RC5 BAUDCON.4 = 1 ; Transmit inverted data to the Tx pin ANSELC = 0 ; Digital only for all PortC pins TRISC = 0 ; Make all PORTC pins output TRISA = %00000010 ; Make all pins output except for RA1 (trim pot input) ANSELA = %00000010 ; Analog on PORTA.1 (AN1) only FVRCON = 0 ; Fixed Voltage Reference is disabled ADCON0 = %00000101 ; ADC (analog-to-digital) is enabled on AN1 (RA1) only PAUSEUS 20 ; wait for the analog switch 'glitch' to die down ADCON1.7 = 0 ; Left-justified results in 8-bits #IFDEF USE_LCD_FOR_DEBUG LCD_INST CON 254 ' instruction LCD_CLR CON 1 ' Clear screen LCD_L1 CON 128 ' LCD line 1 LCD_L2 CON 192 ' LCD line 2 #ENDIF ADCInVal VAR BYTE ; stores ADCIN result read from trim pot Main: gosub Do_ADC pause 100 #IFDEF USE_LCD_FOR_DEBUG ' DO SOMETHING HERE HSEROUT [LCD_INST, LCD_CLR] pause 5 HSEROUT ["ADC val=", DEC ADCInVal, " ", 13, 10] ; Send text followed by carriage return and linefeed #ENDIF GOTO Main Do_ADC: PAUSEUS 50 ' Wait for A/D channel acquisition time ADCON0.1 = 1 ' Start conversion WHILE ADCON0.1 ' Wait for it to complete WEND ADCInVal = ADRESH return
the voltage to the pot is probably fluxuating small amount....... add a good size cap to wiper arm (1 microfarad +-) to smooth voltage.
I added a 1uF, 63V electrolytic cap between the middle wiper arm input to the PIC and GND, but no change. I measured the voltage on the middle wiper arm of the pot and with a reading of '255' I see 4.99V and with '1' I see 0.00V.
Am I doing something wrong with using ADRESH in 8-bit mode?
Interestingly, if I switch to 10-bit resolution on ADC I get values from 5-1023. I think there must be something wrong with my config or code:
Code:#DEFINE USE_LCD_FOR_DEBUG ; comment out for non-debug use ' Vdd -> pin 1 -> +5V ' RC5/Rx -> pin 5 -> EUSART receive ' RC4/Tx -> pin 6 -> EUSART transmit (LCD) ' RA1 -> pin 12 -> trim pot input (1 uF electrolytic cap?) ' Vss -> pin 14 -> GND DEFINE OSC 16 ; Set oscillator 16Mhz DEFINE ADC_BITS 10 ; Set number of bits in result DEFINE ADC_SAMPLEUS 50 ; Set sampling time in uS (was 5) DEFINE ADC_CLOCK 3 ; Set clock source (3=rc) DEFINE HSER_TXSTA 20h ; Set transmit status and control register DEFINE HSER_BAUD 2400 ; Set baud rate ' *************************************************************** ' Device Fuses ' *************************************************************** #CONFIG __config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF __config _CONFIG2, _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LVP_OFF #ENDCONFIG ' *************************************************************** ' Initialization ' *************************************************************** OSCCON = %01111000 ; 16MHz internal osc APFCON0.2 = 0 ; Tx on RC4 for LCD display APFCON0.7 = 0 ; Rx on RC5 BAUDCON.4 = 1 ; Transmit inverted data to the Tx pin ANSELC = 0 ; Digital only for all PortC pins TRISC = 0 ; Make all PORTC pins output TRISA = %00000010 ; Make all pins output except for RA1 (trim pot input) ANSELA = %00000010 ; Analog on PORTA.1 (AN1) only FVRCON = 0 ; Fixed Voltage Reference is disabled ADCON0 = %00000101 ; ADC (analog-to-digital) is enabled on AN1 (RA1) only PAUSEUS 20 ; wait for the analog switch 'glitch' to die down ADCON1.7 = 1 ; Right-justified results in 10-bits #IFDEF USE_LCD_FOR_DEBUG LCD_INST CON 254 ' instruction LCD_CLR CON 1 ' Clear screen LCD_L1 CON 128 ' LCD line 1 LCD_L2 CON 192 ' LCD line 2 #ENDIF ADCInVal VAR WORD ; stores ADCIN result read from trim pot compVal VAR WORD ; stores last-changed ADC value GOSUB Do_ADC compVal = ADCInVal ; set initial compare value Main: gosub Do_ADC pause 100 #IFDEF USE_LCD_FOR_DEBUG If (compVal > (ADCInVal + 1)) or (compVal < (ADCInVal - 1)) THEn ' If this method of reading ADC is as rock-solid as it appears. ' then I can remove the +/- 1 before doing anything; it would be ' IF ADCInVal <> compVal ' DO SOMETHING HERE compVal = ADCInVal endif HSEROUT [LCD_INST, LCD_CLR] pause 5 HSEROUT ["ADC val=", DEC ADCInVal, " ", 13, 10] ; Send text followed by carriage return and linefeed #ENDIF GOTO Main Do_ADC: PAUSEUS 50 ' Wait for A/D channel acquisition time ' (does this need to be the same as ADC_SAMPLEUS?) ADCON0.1 = 1 ' Start conversion WHILE ADCON0.1 ' Wait for it to complete WEND ADCInVal.HighBYTE = ADRESH ADCInVal.LOWBYTE = ADRESL return
If I remove the DEFINEs usually associated with the ADCIN function:
and use Fosc/8 as the timer:Code:'DEFINE ADC_BITS 10 ; Set number of bits in result 'DEFINE ADC_SAMPLEUS 50 ; Set sampling time in uS (was 5) 'DEFINE ADC_CLOCK 3 ; Set clock source (3=rc)
Then I get 0-255. If I do the same for 10-bit resolution, though, I now get 1-1023.Code:ADCON1 = %00010000 ; Left-justified results in 8-bits; Fosc/8 as timer
Bookmarks