KhaledOsmani
Full Member level 6
- Joined
- May 4, 2014
- Messages
- 384
- Helped
- 1
- Reputation
- 2
- Reaction score
- 1
- Trophy points
- 18
- Activity points
- 3,933
Khaled;
what you are proposing is called "polling".
Using Brian's example, this is similar to a person that is making several chores around the home:
1) you are preparing food in the kitchen,
2) you go outside and water the trees,
3) go to check the baby in its room to see if it is sleeping, and
4) then you go to the room where the phone is located to see if it is ringing......always in that order.
Every task takes some fixed time, and because you are doing them sequentially, they each have to wait the turn.
Now imagine............. that you have just walked into the kitchen and the phone rings. You ignore it and continue working in the kitchen. Then you still ignore it and go water the trees outside, then you go and watch the baby. Then and only then, you go out and check if the phone is ringing.
You know what is going to happen, right? You may be able to answer the phone, but most likely you will miss the call.
That my friend, is the purpose of interrupt routines in controllers. You will have to use one sooner or later. I strongly advise you that, as part of your learning process, learn how to use them.
Let me elaborate a bit more detail:
1. Microprocessor receives an interrupt; it issues an acknowledgement. Without this acknowledgement, the interrupt is said to be ignored. To receive an interrupt, interrupts must be enabled.
2. Microprocessor queries the source of the interrupt and the source must identify (this is not applicable in the current case) but will be important to know because in many cases interrupts are multiplexed and the microprocessor has only one pin reserved for interrupts. Interrupt controllers are basically doing this job of multiplexing and assigning the priorities of the different sources. In such cases, the controller tells the microprocessor the original source that caused the interrupt.
3. Microprocessor does some homework and housekeeping: it disables interrupt for the time being and checks whether any other interrupt is pending to be serviced. It may also see whether any other interrupts are currently being processed. Then, depending on lots of considerations, it decides to allow the interrupt. It simply branches to a subroutine (ISR) corresponding to the source of interrupt. As usual, it will save the registrars and the program counter on the stack so that after the interrupt service routine is completed, it knows where to go...
4. Once it enters the interrupt service routine, it is usual to enable interrupts again (all this while, the microprocessor was unable to accept fresh interrupts) unless you are doing a critical job and do not want to be disturbed. This service routine has usual codes and returns back with a special code (so that the compiler knows that you are returning from an interrupt). The important thing is that it is possible to have interrupt within an ISR and that may be nested quite deep. Unless, of course, you do not enable interrupts when you enter the ISR, which is not a good practice because you may miss some important interrupts. Usually you can block interrupts with lower priorities than the current one being serviced.
5. There are software interrupts that are called from subroutines and they act like subroutines and I do not know much about them. They are very useful when you want to run multiple tasks or threads on the same CPU (not applicable for the current case).
6. For all practical purposes, the interrupt on the PIC pins are just calls to some subroutines. Do not put too many instructions in the ISR. 1-5 statements are fine without calls to user routines.
I could do with Schmitt trigger's "person" here, it sounds like someone useful to have around. :lol:
Khaled, your understanding is good and accurate. Oshonsoft automatically save the critical registers when an interrupt occurs and put them back to their original values with the RESUME statement. There is a danger with interrupts that registers or variables get changed by the instructions in the ISR so when it finishes and the main program continues, they may contain unexpected values. Remember that the main program is suspended by the interrupt so it has no knowledge that something might be altering things 'behind it's back'.
PIC18F devices have two 'levels' of interrupt called low priority and high priority. Essentially they are the same and low priority is compatible with most other PIC families. The difference between them is that high priority interrupts can suspend low priority ones, just like low priority can suspend the main program flow. For your application you do not need to use two priority levels, one is sufficient. In the 18F4520, low priority interrupts make the program jump to address 0018h and high priority interrupts make it jump to 0008h. These are called the interrupt vectors, the interrupt code itself doesn't have to be at those addresses, they are usually used to hold jump instructions to the real ISRs where there is more space to hold larger code.
The golden rule with interrupts is to get out of them as fast as possible. Each 'level' of interrupts switches off it's corresponding GIE bit to prevent other interrupts occuring and the RESUME statement turns it back on again. While the GIE bit is turned off, other interrupts may be requested (their interrupt flags set) but no action will be taken. If after RESUME, there are any set flags, they will immediately trigger another interrupt. It follows that if you spend too much time in an ISR, there is a good chance you will miss repeated interrupts.
The other thing to observe is where the interrupt trigger came from, you already found the RB0 interrupt input but there are many more. If you look in the PIxx registers you will see you can select which ones are active and which ones are assigned to each priority. All you have to do is work out the bit pattern to select the interrupts you need and set the register to that value. When the ISR is entered, the first thing you normally do is check to see which flags are set so you know where the request came from.
I'll see if I can find any example code for you. As I stated earlier, I use 'C' or assembly language for almost all my programming and I don't think I've ever written a 'serious' program in BASIC so I have no examples of my own to share.
Brian.
I could do with Schmitt trigger's "person" here, it sounds like someone useful to have around. :lol:
Khaled, your understanding is good and accurate. Oshonsoft automatically save the critical registers when an interrupt occurs and put them back to their original values with the RESUME statement. There is a danger with interrupts that registers or variables get changed by the instructions in the ISR so when it finishes and the main program continues, they may contain unexpected values. Remember that the main program is suspended by the interrupt so it has no knowledge that something might be altering things 'behind it's back'.
PIC18F devices have two 'levels' of interrupt called low priority and high priority. Essentially they are the same and low priority is compatible with most other PIC families. The difference between them is that high priority interrupts can suspend low priority ones, just like low priority can suspend the main program flow. For your application you do not need to use two priority levels, one is sufficient. In the 18F4520, low priority interrupts make the program jump to address 0018h and high priority interrupts make it jump to 0008h. These are called the interrupt vectors, the interrupt code itself doesn't have to be at those addresses, they are usually used to hold jump instructions to the real ISRs where there is more space to hold larger code.
The golden rule with interrupts is to get out of them as fast as possible. Each 'level' of interrupts switches off it's corresponding GIE bit to prevent other interrupts occuring and the RESUME statement turns it back on again. While the GIE bit is turned off, other interrupts may be requested (their interrupt flags set) but no action will be taken. If after RESUME, there are any set flags, they will immediately trigger another interrupt. It follows that if you spend too much time in an ISR, there is a good chance you will miss repeated interrupts.
The other thing to observe is where the interrupt trigger came from, you already found the RB0 interrupt input but there are many more. If you look in the PIxx registers you will see you can select which ones are active and which ones are assigned to each priority. All you have to do is work out the bit pattern to select the interrupts you need and set the register to that value. When the ISR is entered, the first thing you normally do is check to see which flags are set so you know where the request came from.
I'll see if I can find any example code for you. As I stated earlier, I use 'C' or assembly language for almost all my programming and I don't think I've ever written a 'serious' program in BASIC so I have no examples of my own to share.
Brian.
You can do it that way but the zero crossing signals are already at 5V (or very close) so you don't need to use the ADC unless you are measuring the current as well. If a current measurement is needed rather than just knowing the phase difference, you need to adopt a different approach because the current monitor is only checking the polarity at the moment (zero crossing is when it reverses).
At the moment, the waveform from the LM358 will be a square wave, with the same timing as the sine wave from the CT transformer but it's amplitude will be constant. There isn't much point in measuring the voltage if it's constant! To measure the current you need to convert the AC voltage in the CT secondary to a DC voltage the ADC can measure. It is possible to measure it as AC by offsetting the CT voltage but it's more complicated electronically and in software. Converting AC to DC then measuring it is far easier. It should be possible to measure voltage and the zero crossing by using both op-amps in the LM358 so it doesn't need too many extra parts
Please confirm first that you need to measure the current as well as the phase.
Brian.
Do that, but in step 3 do not use the ADC result, just read the logic state of the pin instead.How about to make a "transient" test, just to testify results as follows:
1. I will not rush the PIC into any task
2. The first and last task is about measuring power factor for the 60W fan
3. Make a normal subroutine, using ADC from PORTA.2 and PORTA.3
4. Start a timer when HIGH logic is there on PORTA.2
5. Stop the same timer when HIGH logic is there on PORTA.3
6. Make the conversion for the timer into a phase angle as: 1/50 corresponds to 360 degrees then timer corresponds to C degree
7. Make cos(angle of timer)
8. Sends to display
That makes it much easier because you already have the logic level signals to use. If you wanted to measure the current it would need a linear amplifier and rectifier as well.
All you need to do is use one signal (Voltage ZC) to start the timer and the other (current ZC) to stop it.
Do that, but in step 3 do not use the ADC result, just read the logic state of the pin instead.
See if you can get it to work, it will be easy to convert it to use interrupts later.
Brian.
That makes it much easier because you already have the logic level signals to use. If you wanted to measure the current it would need a linear amplifier and rectifier as well.
All you need to do is use one signal (Voltage ZC) to start the timer and the other (current ZC) to stop it.
Do that, but in step 3 do not use the ADC result, just read the logic state of the pin instead.
See if you can get it to work, it will be easy to convert it to use interrupts later.
Brian.
loop:
If PORTC.0 = 1 Then
ASM: BCF T0CON,T08BIT
ASM: BCF T0CON,T0CS
ASM: BSF T0CON,TMR0ON
If PORTC.1 = 1 Then
ASM: BCF T0CON,TMR0ON
ASM: RETURN
Else
Goto loop
Endif
Endif
Lcdout "Htime= ", #TMR0H
Lcdcmdout LcdLine2Home
Lcdout "Ltime= ", #TMR0L
WaitMs 1000
End
The timer is part of the silicon, you have to do some configuring so it counts at the speed you want then it runs by itself. What you need to do is reset it to zero when the voltage ZC is detected then read it when the current ZC is detected. You can't use the value in the timer directly because it will be a binary number and probably doesn't translate to a displayable character, you have to do some math on it first.
For example: if the AC is 50HZ, each cycle takes 20mS (1/50 seconds). If you want to measure to an accuracy of 1 degree and have a maximum phase angle of 359 degrees, you would have to make the timer increment from 0 to 359 in 20mS so it would have to run at 18,000 counts per second (18KHz). If you wanted a 0.1 degree accuracy you would count at 10 times the frequency.
I've been busy in meetings all day and it's late at night here so I'm too tired write any sensible code right now but I have copied your 'first step code' in to the compiler and I'll look at it in the morning. I'm in danger of falling asleep at the keyboard so if I continue you will probably get pages of zzzzzzzzzzzzzzzzzzzzzzzzzzz............:smile:
Brian.
Define CLOCK_FREQUENCY = 4
Dim t0count As Word
Dim phase_angle As Word
Dim scaling_factor As Word
scaling_factor = 1 'conversion factor from count to phase
'initialize the pic registers
Gosub setup_pic
'initialize the display
Lcdinit
'main program loop
loop:
If PORTC.0 = 1 Then
TMR0L = 0 'reset the count at voltage ZC
TMR0H = 0
Endif
If PORTC.1 = 1 Then
T0CON.7 = 0 'stop the count at current ZC
t0count = TMR0H * 256
t0count = t0count + TMR0L
phase_angle = t0count / scaling_factor
Lcdout "Phase= ", #phase_angle
T0CON.7 = 1 'start the Count again
Endif
Goto loop
End
setup_pic:
TRISC = 0x03 'TRISC has bits 0 And 1 As inputs
T0CON = 0x80 'T0CON enabled, 16 Bit, internal clock, prescale 1: 2
Return
WaitMs 1000
LCDOUT "Phase= ", #phase_angle
Before going further, the results you see may be due to restrictions in the Oshonsoft licence. Please do this and tell me what you see:
1. In the main window, click "Help".
2. then click "View License Information"
3. it should open a small window with your name in it. Click the "info" button at the bottom and tell me what it shows.
Some of the math routines may give different results depending on which sections of the license are activated.
Sorry for the delay, I tried to ask this earlier but got called away before I could send the message.
Brian.
The license files are locked to the name of the person who purchased them and the compiler files on the public download page at Oshonsoft's web site are demo versions. When you buy the program and/or licenses a link is sent to the registered versions and customized '.reg' files.
If you want to continue using BASIC, I strongly suggest you at least buy the floating point support, the others are useful but not essential. What is happening when you see those number in post #76 is you are seeing only the integer part of the division result.
I'm not sure if BASIC is mandatory for your project but I find it very restrictive. If you can change to 'C' you will find programming is much easier.
Brian.
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?