PDA

View Full Version : Voltage output from PIC16f628A



bennamanna
- 1st November 2006, 02:08
Hi all,

I am very new to pics and programming. I have a PIC16f628A of which I want to use for a project. I wish to have 2 voltage outputs. One 0-2.5v and the other 0-5v. I wish to be able to to send commands from a PC via rs232 to set these voltages. I am using picbasic for the project. Can anyone give me some guidance or some code of a similar project that I can learn from? The pc coding is fine. I am using VB and comm control.

Thanks,

Ben

mister_e
- 1st November 2006, 04:42
Tons of different way

Scheme 1:
Use HPWM to produce your 0-5 volt
Use a op-amp and use the Vref signal to produce you 2nd 0-2.5 volt. If you can deal with the resolution.. it works.

Scheme2:
Use HPWM for your 0-5 volt
Create a timer based PWM to create the second PWM channel

Scheme3:
Use 2 DAC. MAX437 is simple and cheap

Scheme4:
Use Darrel Taylor Multi SSPWM. So you may produce few different voltage output.

Scheme5:
Create you own multi PWM output based on Timer interrupts.

Scheme6:
Use a PIC with 2 CCP module.. hence two PWM output. 16F876,16F877 and the list is long enough to fill the screen here :D

Scheme7:
Use 2 PIC with 1 PWM. 1XPIC16F628 + PIC 12F683 talking together.

There's some others but it should be enough to start?

bennamanna
- 7th November 2006, 22:44
Gday,

Thanks for your reply. I am testing some of your methods. I have a few queries.

1. This voltage i require is to be read by a vehicle ecu. If you use PWM will it see that as a voltage or will it see the pulses?

2. I have put together some code to test the PWM output. It is giving a PWM signal as expected but when I input a figure in a terminal it does not put the same figure to the display or PWM output. It does change but not as expected. Any ideas why?

Thanks


INCLUDE "modedefs.bas" ' Include serial modes
SI VAR PORTB.1 ' Serial Input pin
B0 VAR BYTE
Define OSC 10

Define LCD_DREG PORTA ' RA0..3
Define LCD_DBIT 0
Define LCD_RSREG PORTA ' RA6
Define LCD_RSBIT 6
Define LCD_EREG PORTA ' RA4
Define LCD_EBIT 4
Define LCD_BITS 4
TRISA = 0
TRISB = 0
CMCON = 7

Pause 1000 ' Wait for LCD to startup



duty VAR WORD ' Duty cycle value (CCPR3L:CCP3CON<5:4>)


TRISB.3 = 0 ' Set PORTB.5 (CCP3) to output
CCP1CON = %00001100 ' Set CCP3 to PWM
T2CON = %00010101 ' Turn on Timer2, Prescale=4

' Use formula to determine PR2 value for a 1KHz signal,
' 4MHz clock, and prescale=4. (4E6/(4*4*1E3))-1=249

PR2 = 249 ' Set PR2 to get 1KHz out

' Use formula to determine CCPR3L:CCP3CON<5:4> value for
' ends of range 20% to 80%. (249+1)*4*0.2=200 (20% value)
' (249+1)*4*0.8=800 (80% value)


duty = 200 ' Set duty cycle to 20%

loop: SerIn SI,T9600,duty
CCP1CON.4 = duty.0 ' Store duty to registers as
CCP1CON.5 = duty.1 ' a 10-bit word
CCPR1L = duty >> 2

'duty = duty + 5 ' Increase duty cycle
LCDOut $FE,1 ' Clear LCD screen
LCDOut # duty ' Display line 1
pause 1000
' Since the total sweep of duty is 600 (800-200) and
' we are adding 10 for each loop, that results in 60
' steps min to max. 1 second divided by 60 = 16.67mS

Pause 17 ' Pause 1/60 of second

'IF (duty < 900) Then loop ' Do it again unless 80% duty cycle

'duty = 200 ' Reset to 20% duty cycle

GoTo loop ' Do it forever

mister_e
- 7th November 2006, 23:07
your CCP definition are fine for 4MHZ, but not for 10MHZ.

download this tool bellow
http://www.picbasic.co.uk/forum/showthread.php?t=4994

it will give you some answer.


1. This voltage i require is to be read by a vehicle ecu. If you use PWM will it see that as a voltage or will it see the pulses?
More than likely it will see pulses. You have to convert it to pure DC with a simple RC filter... better if you add a op-amp buffer in between.

bennamanna
- 8th November 2006, 00:15
Gday,

Thanks again for your reply. I will use a rc filter as you suggested.

I have downloaded your calc. It looks like it would be verry usefull. As stated I am a beginner ;- ( Could you please step me through what I have to enter in to your calc and my code to fix it? I will learn this way.

Thanks,

Ben

mister_e
- 8th November 2006, 03:52
you just need to enter the OSC speed and expected frequency. it will give you...
<img src="http://www.picbasic.co.uk/forum/attachment.php?attachmentid=1168&stc=1&d=1162957701">
There, you have the
prescaller => 1:16 => see T2CON setting in your datasheet
PR2 => 155 => directly

It also give you the value for 100% duty cycle => 625

If you want to set different DutyCycle, move the scroll bar at the top right. The duty value will be reported in the 'results' section at the bottom.

Not much.

bennamanna
- 8th November 2006, 22:07
Gday again,

Thanks for that info. I changed the PR2 as per your calculation. It still does not seem to give the same value as I enter in the terminal application. If I am correct in my coding, if I send it 100 with a terminal app 100 should display on the LCD and it should set the duty cycle to 100. This is not the case. It says 34 on the LCD and reflects that in the duty cycle.

Any ideas?

Thanks,

Ben

mister_e
- 9th November 2006, 03:27
I don't know wich terminal software you're using but be sure it send ASCII character and use the right modifier in your Serin/Serin2/DEBUGIN/HSERIN line.

Look for # or DEC.

Also, make sure your terminal software don't send cr and lf character.

Once you're sure of it, you should have better results.

If you send 100 and receive it correctly, you should have a 16% duty cycle.

bennamanna
- 9th November 2006, 04:43
Gday,

I am using serial communicator that is with microcode studio. I cant see a setting to ensure it is sending ascii. I made sure it was not sending cr and it made no diference.

The code I am using is below.

NCLUDE "modedefs.bas" ' Include serial modes
SI VAR PORTB.1 ' Serial Input pin
B0 VAR BYTE
Define OSC 10

Define LCD_DREG PORTA ' RA0..3
Define LCD_DBIT 0
Define LCD_RSREG PORTA ' RA6
Define LCD_RSBIT 6
Define LCD_EREG PORTA ' RA4
Define LCD_EBIT 4
Define LCD_BITS 4
TRISA = 0
TRISB = 0
CMCON = 7

Pause 1000 ' Wait for LCD to startup

duty VAR BYTE ' Duty cycle value (CCPR3L:CCP3CON<5:4>)

TRISB.3 = 0 ' Set PORTB.5 (CCP3) to output
CCP1CON = %00001100 ' Set CCP3 to PWM
T2CON = %00010101 ' Turn on Timer2, Prescale=4

PR2 = 155 ' Set PR2 to get 1KHz out
duty = 100 ' Set duty cycle to 20%

loop:
SerIn SI,T9600,,duty
if duty > 625 then
LCDOut $FE,1 ' Clear LCD screen
LCDOut "Duty to great" ' Display line 1
goto loop
endif

CCP1CON.4 = duty.0 ' Store duty to registers as
CCP1CON.5 = duty.1 ' a 10-bit word
CCPR1L = duty >> 2

'duty = duty + 5 ' Increase duty cycle
LCDOut $FE,1 ' Clear LCD screen
LCDOut # duty ' Display line 1

GoTo loop ' Do it forever

Any other ideas why it is not receiving the same as I send it?

Thanks,

Ben

sayzer
- 9th November 2006, 07:14
hi Ben,

Since our PICs are serial processors, at least for now, and must execute the instructions serially, that is to say one line or instruction at a time, you will never get Serin and Serout commands working at the same time.

If you use hardware USART, then it will be working in the background, so that you can receive something at the same time you send it.


-----------------------------

mister_e
- 9th November 2006, 17:00
As i said before... look for # modifier... it convert your ASCII string to a DECIMAL value.

bennamanna
- 9th November 2006, 20:27
Hi sayzer,

Thanks for your reply. I did not think that my code was trying to use ser in and out at the same time? Could you indicate where I am doing this? Thanks mate.

mister_e,

Thanks once again. I'm sorry if I'm making you repeat your self. As stated before I am a beginner. I had however already played with # in my code. I tested it with and without. With out # all i get is jargon.

Thanks,

Ben

mister_e
- 10th November 2006, 00:59
T2CON = %00010101 ' Turn on Timer2, Prescale=4
'
'
'
duty = 100 ' Set duty cycle to 20%

1. your prescaler is not set to 1:16 as said in the calc. Now, it's set to 1:4. Have a look in datasheet section 8.0 register 8-1 T2CON. you'll discover you need to use T2CON=%00000110

2. duty=100 set a duty cycle of 16%... still as per the calc. 20% Duty=125


SerIn SI,T9600,,duty
i think it's invalid.

you should try

SerIn SI,T9600,#duty

In Microcode Studio serial communicator, you have access to the settings. Right to 'send' button there's a little arrow.. click on it, go to line terminator, then check 'No terminator'

bennamanna
- 12th November 2006, 23:39
Gday,

I changed the items you found to be in correct. It still will not output what I send via RS232. It comes up with other numbers. I will repost the code I have ended up with below.

INCLUDE "modedefs.bas" ' Include serial modes
SI VAR PORTB.1 ' Serial Input pin
B0 VAR BYTE
Define OSC 10

Define LCD_DREG PORTA ' RA0..3
Define LCD_DBIT 0
Define LCD_RSREG PORTA ' RA6
Define LCD_RSBIT 6
Define LCD_EREG PORTA ' RA4
Define LCD_EBIT 4
Define LCD_BITS 4
TRISA = 0
TRISB = 0
CMCON = 7

Pause 1000 ' Wait for LCD to startup

duty VAR word ' Duty cycle value (CCPR3L:CCP3CON<5:4>)

TRISB.3 = 0 ' Set PORTB.5 (CCP3) to output
CCP1CON = %00001100 ' Set CCP3 to PWM
T2CON = %00000110 ' Turn on Timer2, Prescale=6

PR2 = 155 ' Set PR2 to get 1KHz out
duty = 125 ' Set duty cycle to 20%

loop:
SerIn SI,T9600,,# duty

if duty > 625 then
LCDOut $FE,1 ' Clear LCD screen
LCDOut "Duty to great" ' Display line 1
goto loop
endif

CCP1CON.4 = duty.0 ' Store duty to registers as
CCP1CON.5 = duty.1 ' a 10-bit word
CCPR1L = duty >> 2

'duty = duty + 5 ' Increase duty cycle
LCDOut $FE,1 ' Clear LCD screen
LCDOut # duty ' Display line 1

GoTo loop ' Do it forever



Any other ideas?

Thanks,

Ben

mister_e
- 13th November 2006, 04:18
Try this one. I don't use LCD but echo the results to the PC.


@ __CONFIG _HS_OSC & _MCLRE_ON & _LVP_OFF & _WDT_OFF & _PWRTE_ON & _BODEN_ON
DEFINE OSC 10

CMCON = 7
PORTA = 0
PORTB = 0
TRISA = 0
TRISB = %00000010

DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1
DEFINE HSER_SPBRG 64 ' 9600 Baud @ 0.16%
DEFINE HSER_CLROERR 1 ' Clear overflow automatically

Duty VAR WORD ' Duty cycle value (CCPR1L:CCP1CON<5:4>)

CCP1CON = %00001100 ' PWM mode
T2CON = %00000110 ' Turn on Timer2, Prescale=1:16

PR2 = 155 ' Set PR2 to get 1KHz out
duty = 125 ' Set duty cycle to 20%
GOSUB ChangeDuty

Loop:
HSerIn [DEC Duty]
IF Duty > 625 THEN
HSEROUT ["Duty too high... MAX = 625",13,10]
ELSE
GOSUB ChangeDuty
HSEROUT ["Duty=",DEC Duty,13,10]
ENDIF
GOTO Loop

ChangeDuty:
CCP1CON.4 = Duty.0 ' Store duty to registers as
CCP1CON.5 = Duty.1 ' a 10-bit word
CCPR1L = Duty >> 2
RETURN

and read the FAQ about the fuse config... i think it's your main problem.

So far, it's working here.