PDA

View Full Version : PIC - receive data while pulsing pin from low to high and from high to low



skaarj
- 13th April 2014, 18:43
Hello

The problem I present here is a little weard because I could not find any documentation for anybody else needing this.

My device must measure spectrography data while pulsing a high power light source. So the code looks like this:

start
- high PORTA.0 pin to start laser
- read measurements & output to PORTC
- pause x
- low PORTA.0 pin to turn off laser
- read measurements & output to PORTD
- pause x
- goto start.

or some PBP sample code:

define OSC 20
result var byte
pause_time var word : pause_time = 3000 ; (3.000 pulses per second)
period_ms var byte
period_us var byte

main:
high porta.0
gosub ADC_read
portc = result
gosub pause_for_period_of_time
low porta.0
gosub adc_read
portD = result
gosub pause_for_period_of_time
goto main

adc_read:
; read stuff from some high speed soviet golden capsule military aircraft chip connected to 8 bit PORTB
; high portE to enable chip, read the portB, low portE to disable the chip
return

pause_for_period_of_time:
period_ms = pause_time.byte1
period_us = pause_time.byte0

; pause the program so I can totaly get the frequency I specified at beginning (3.000Hz or 4.231Hz or something between 1Hz and 10Hz with three digits after decimal point)

pause [asylum/madhouse formula without floating point unit]

return


The problem is I must somehow redefine "pulsout" function so I can take measurements immediately after the pin is high, and again to take measurements after the pin is low. Or somehow find a formula to determine the period formula from the given frequency by using digital logic, as this pic does not have a FPU. Or to get in contact with Jedi Master of Assembler.

My XTAL frequency is 20MHz to be able to work with microseconds.

the program works, I can gather data but I did something like this:
pause for sine fraction of period in ms
for i=0 to 256 : pause "i" times the period in US : next i.
This is garbage but at least I have a variable pulse and I can do measurements between pin going from low to high and from high to low.

Any ideas will be welcomed.

Demon
- 13th April 2014, 19:38
Have you considered using DT INTERRUPTS for the timing?

Have you considered using the PORT ON CHANGE feature to detect high-low and low-high? (check datasheet, you don't mention which PIC you are using).

Robert

skaarj
- 13th April 2014, 19:48
Hello

I am beginner in pic stuff. The pic I am using is the classic 16F877.

Low to high and high to low detection is everything I get when I search the internet. Low to high and high to low triggering at a given frequency is what I wish to achieve. And of course a jump to additional code between these steps.
I'm working at some assembly code which is hard, I am used to do this stuff in old school fashioned way (logic gates). So far I understood bsf and bcf. I need a loop repeating "n" times some nop to achieve the desired delay.

Thank you for your suggestion. I'm searching now for DT interrupts.

Demon
- 13th April 2014, 21:20
http://www.picbasic.co.uk/forum/showthread.php?t=18505

Robert

skaarj
- 13th April 2014, 23:00
Thank you very much for pointing me to DT Interrupts. Much to learn, useful examples, a lot of help for future work. Unfortunately those procedures work with a fixed frequency. New frequency means recompile, reprogram and power up. Changes in frequency while running do not work. This is pointed in the examples.

Then I tried to split the pulse time (miliseconds, var WORD) in pulse.byte0 + 256 x pulse.byte1. Calculated period in miliseconds and period in microseconds, applied the delay. Still trouble calculating the period, too many clock cycles lost with DIV and DIV32. I gave up.

Master board now sends the period directly. No more period calculated from given frequency, no precision wasted with DIV and DIV32.
Problem solved.

Demon
- 14th April 2014, 03:06
Ideas:

(Note my 16F877 datasheet is not recent)

Port B has interrupt on change feature, page 132 of 218. I would use that port to check for transitions.

The 16F877 has 3 timers, I would use one for low-high transitions and another for high-low.

When port B senses a change, check if going high or low and start the appropriate timer.

At next port B change, check which transition it is, then check if you started that timer, and if yes then check the time elapsed on the timer.

If at the desired frequency, stop timer and trigger whatever event you want, or restart timer again. This way you can check going high and low transitions at the same time. You can check if within a range of desired frequency also, possibly a 5% tolerance - depends on your needs. You can also use a counter to check how many pulses was detected at that frequency (stability test - reset if less than X transistions).

It may be a simplified approach, but it may be all you need for your application. You can use DT INTERRUPTS to control the timers (it can control a LOT of things), it makes things so much easier than trying to figure what registers to set in the datasheet.

About DT interrupts, make sure you use the version for 16F PICs from DT's site (it's all labelled properly).

If the maximum oscillator speed of 20 MHz of the 16F877 is not enough, consider an 18F. I used the 16F628 and 16F877 when I first started, now I use the 18F24K22 series, they can run at 64 MHz on internal oscillator.

One last note, don't try to do everything at once. Start with one part of your logic, and build on it as you prove it works. Test each new section as you add them. Personally, I test them individually in small programs, then incorporate them in the main program as they are tested OK.

Good luck!

Robert

Demon
- 14th April 2014, 03:17
... Unfortunately those procedures work with a fixed frequency. New frequency means recompile, reprogram and power up. Changes in frequency while running do not work. This is pointed in the examples.
...

About this, if you use a variable instead of constant when you check the elapsed time on a timer, you can change the value of this variable within your program, no need to recompile.

A simple method is INCREASE and DECREASE buttons than can change the value of your variable. Start at a default value, then an LCD is practical to display the new value of the variable. Using multiple pairs of buttons make changes easier; one pair for change of 1, one pair for 10, one pair for 100, whatever your needs are.

You might only need buttons that set at specific values.

Robert

HenrikOlsson
- 14th April 2014, 06:36
Hi,
I might be missing something here but where does IOC fit in?
The tast is to generate pulses with a specific and precise delay during which the ADC measurements will performed. There's no pulses comming into the PIC as far as I understand.

Can you be a little more specific on the dynamic range of the output frequency? You mention 1-3000Hz down to 3 decimal places, is that a hard requirement? (I haven't crunched any numbers yet but I don't think that's doable).

Here's what I'm thinking:
* Calculate a suitable timer prescaler and timer value for the needed delay and set the timer up accordingly
* Set output high
* Start the timer
* Go do the ADC conversion and output result.
* Poll timer interrupt flag in tight loop
* Set output low
* Stop timer, reload value for correct delay, restart
* Go do the ADC coversion and output result
* Poll timer interrupt flag in tight loop
* Rince and repeat.

The issue here is that with a very low frequency (1Hz) there might not be enough bits in the timer/prescaler and you'd have to resort to counting multiple overflows (very doable but adds a bit of complexity). At the other end of the spectrum (3000Hz) there won't be enough resolution to resolve 2999.998 or 2999.999Hz. In fact, there probably won't be at the low end either.

Finally, DT-Ints is in no way restricted to "fixed frequency". Perhaps the examples shown is USING a fixed frequency but that's not the same thing. Anyway, I think DT-Ints is probably overkill and will add unneccesary overhead for the requirements stated.

/Henrik.

Demon
- 14th April 2014, 12:42
I think you are right Henrik. I read too much in this:


This is garbage but at least I have a variable pulse and I can do measurements between pin going from low to high and from high to low.

Post 1 only mentions from 1 to 10Hz pulse out, very doable on 16F877.

Robert

HenrikOlsson
- 14th April 2014, 16:01
Hi Robert,
You are correct. I misread 3.000 as 3000, duh....
Well, then perhaps its doable after all.

/Henrik.

skaarj
- 14th April 2014, 20:47
Thank you for your help

The system I am working on is composed of 16 PICs (16F877) and a common data bus (port expanders, FIFO structures). Each PIC (on its own board) does its job without waiting to sync with the others. If any microcontroller needs data (settings from menu board), it pulls it out from the common bus. If it needs to send something, it just access the data bus, addresses some register and stores whatever it needs to store - usually to the menu board for slooooooowly display it on the LCD. I can not offer any decent details as more than half of the components are in golden capsules encoded in Cyrillic and are undocumented on internet. It is a monster. Instrumentation amplifier was built with subminiature vacuum tubes (used in MIG aircrafts). Stuff found in recycling companies back yards, waiting to be crushed and melted.
One PIC is the master, it sends data to the bus according to the menu setup. Another PIC pulses the laser according to whatever frequency the master wants (laser is glass tube type, soviet made, 15 kW power supply required) and acquires the measurements. Another one reads the bus and sends measurements out on a serial port. The other PICs get the measured data and extract whatever component they are required, apply correction methods, temperature adjust, integrate the result and output some numbers. In the end the system can read up to 13 different hydrocarbon gas components from the analysed mixture. This is an experimental cheap PIC-based chromatograph (measure gas components for well drilling industry), cheaper than commercial ones (excepting that huge laser my university council is too lazy to change with a new, solid state based).
Now: from the "menu" board the "pulse frequency" was transmitted on 16-bit resolution. From the menu this frequency can be changed. The measuring board PIC had to calculate the "period" between pulses, so it can read the incoming analog data as smooth as possible. I just changed the menu section to send pulse in miliseconds (!6 bit) and microseconds (another 16 bit) through the common bus. Like an oscilloscope with time base setup. Now it just reads two numbers and it does "pause number_1" and "pause_us number_2". Problem is that each gas component has its own "small piece on the input sinusoide" at its own frequency (between 2 and 10Hz, again precision is three digits after decimal point). Pulse changes are now done automatic, no more manual adjust from menu board. Instrumentation amplifier controls (gain, integrate, input/output signal division) is done with electronic potentiometers. Each component has its own system settings. No more wasted clock cycles for period calculations in the loop. Monster works fine, gas components come out in the right percentages with three digits after decimal point.

Before asking "why so many PICs when you could do it with something faster", I must say this was a project for our madhouse asylum crazy engineering team here (for example young students in love with sinclair spectrums, vacuum tubes or PDP mainframes in the age of tablets and 4G services) who were asked to demonstrate that electrical engineering is still not limited by hardware, it depends only by people involved. Whoever big boss' pockets will be filled after taking away our project, that's another story.