- Joined
- Jul 4, 2009
- Messages
- 16,259
- Helped
- 5,140
- Reputation
- 10,309
- Reaction score
- 5,124
- Trophy points
- 1,393
- Location
- Aberdyfi, West Wales, UK
- Activity points
- 137,603
hmmm, i managed to watch the youtube video, despite very slow internet here. They work on a slightly different principle to what you are trying. Before going further, can you tell me what hardware you have connected to the sensors. I need to know what there is between your tx pin and the transmitting transducer and also what you have between the receiving transducer and the rx pin. This is critical to the way it works.
I don't think the clock signal is the problem and certainly 100mhz is far higher than necessary. You present code will not loop so you can't take continuous readings. The pwm will be turned off and the program will loop forever without taking any further measurements after the first interrupt occurs. May i suggest you rearrange the code slightly like this:
1. Create a global variable, lets call it "measurementtaken", set its value to zero.
2. In the interrupt routine, stop timer 0 from counting, copy the values in timer 0 to a variable, make measurementtaken = 1, stop the pwm.
3. In the main() routine, set up the pwm and other pic registers.
4. Set timer 0 to zero
5. Turn the pwm on.
6. Start a while(1) { loop
7. Use "if(mymeasurementtaken) {report the reading in the variables you set in the interrupt routine then set measurementtaken = 0, clear timer 0 then turn the pwm on again}
8. Close the while loop
this will take repeated measurements between interrupts and you can take as long as needed in step 7 to report the value by lcd or serial link. Steps 4 and 5 are to ensure the first measurement is valid, from then on the same steps are taken inside the while loop but only after the measurementtaken variable lets it know that an interrupt occurred and they need to be prepared again.
Brian.
//INTCONbits.INT0IF =0; //The INT0 external interrupt CLEARED.
#include <p18f2520.h> //MCU IN USE
#include <string.h> //???
#include <timers.h> //???
#include <stdlib.h> //???
#include <pwm.h> //INCLUDE PWM TIMER
int result;
int timeL;
int timeH;
void high_isr(void); // High priority interrupt service routine
#pragma code high_vector=0x08 // High priority interrupt vector
void high_vector(void)
{
_asm goto high_isr _endasm //JUMP TO INTERRUPT ROUTINE
}
#pragma code //RETURN TO DEFAULT CODE SECTION
#pragma interrupt high_isr
void high_isr(void) // high Priority Interrupt Routine
{
PORTBbits.RB2=!PORTBbits.RB2; //toggle LED
//T0CONbits.TMR0ON =0; //STOP COUNTER
//result = ReadTimer0(); //READ VALUE OF COUNTER
//timeL = TMR0L; //Save lower byte to variable
//timeH = TMR0H; //Save higher byte to variable
//ClosePWM1();
//CloseTimer0();
//TMR0L=0b00000000; //TIMER0 STARTING BITS AT 0
//TMR0H=0b00000000; //TIMER0 STARTING BITS AT 0
//INTCONbits.INT0IF =0; //The INT0 external interrupt CLEARED.
}
void main()
{
while(1)
{
TRISA= 0b11111111; // I/O SETTINGS
TRISB= 0b00000011; // I/O SETTINGS
TRISC= 0b10000000; //RC7(R-X) as input & RC6(TX) as output
//CONFIGURE AND ACTIVATE INTERNAL OSCILLATOR
OSCCON = 0b01110000; //select internal clock at 8Mhz frequency
OSCTUNE = 0b01000000; // PLL Mode enable, Total Internal Oscillation = 32MHz
//TIMER0 SETTINGS
OpenTimer0 (TIMER_INT_ON & // On Timer0 Interrupt
T0_16BIT & // 16-bits Mode
T0_SOURCE_INT & // External Clock Source
T0_PS_1_8); // Set Prescaler to 1:1
//INTERRUPT SETTINGS
INTCON=0b00010000; //DISABLE GLOBAL & ENABLE EXT INTERRUPT, Disables the TMR0 overflow interrupt,
INTCON2=0b01000000; //External Interrupt on RISING edge (BIT6)
RCONbits.IPEN =1; //Enable priority levels on interrupts
INTCONbits.GIEH =1; //Global Interrupt Enable
//TIMER0 START BITS @ 0
TMR0L=0b00000000; //TIMER0 STARTING BITS AT 0
TMR0H=0b00000000; //TIMER0 STARTING BITS AT 0
//THIS IS THE SETTING FOR THE PULSE WIDTH MODULATION
//THIS IS IN PIN 13
OpenTimer2(TIMER_INT_OFF & T2_PS_1_1 & T2_POST_1_1); //OPEN PWM. PRESCALAR IS 1:1
OpenPWM1(0xc7); //REFER TO A FOR CALCULATION
SetDCPWM1(400); //REFER TO B FOR CALCULATION
T0CONbits.TMR0ON=1; //START COUNTER!
}
}
Hi, Shalam
You didn't tell people that the travelling time for ultrasound from transmitter to receive is only a few microsecond, did you? And the difference in time between blood and saline is only a few hundred nanosecond.
The guy don't know our situation, his suggestion is on the code, but our problem right now is not on the code. We are testing our sensor and see whether the sensor can detect the time difference between time spent in blood and the saline.
Question - is Neyolight the same person as Shalam or are you both students on the same course?
Your teacher is quite right about the small time differences, that's why I mentioned the phase difference method in an earlier post. To briefly explain, even under ideal conditions there will be a certain time between turning on the PWM and the transmitter reaching full power, the signal doesn't just suddenly appear at full level. Similarly, when the microphone picks the sound up, it will see a rising edge at the start of the arriving 40KHz. The time taken to reach full transmit power and for the receiver output to be able to reach the voltage needed to trigger the interrupt may be many times longer than the time you are trying to measure.
The phase measuring method is far more accurate when the time delay is very short, what you do is keep the transmitter PWM running so it is always sending the 40KHz signal out. You then look at the actual waveform from the receiver rather than just seeing if it's there or not. The waveform will be a delayed copy of the transmitter signal, it would look the same shape but if you plotted the two signals on a graph against a time axis you would see the waveforms were out of step because one was delayed by the distance and medium the signal had traveled through. As the delay changes, the waveforms would move relative to each other, in other words their relative phases change. The task is then to measure the amount of phase change. This is actually easier than it sounds because there is a very simple way of converting phase differences to a measurable signal, all you do is use the logic XOR function with one input being the PWM and the other the signal from the microphone. You can implement the XOR in software or as a simple electronic circuit. The magical property of XOR is it's output is only high when there s a difference between it's two input signals, so it is proportional to the differences in their phase.
You can measure this in two ways, by filtering the XOR output and measuring the analog voltage it produces or by using a timer to measure the length of the difference signal.
The drawback to using this method is the result is cyclical, it can't detect which cycle it is comparing, it will give the same result if the delay is say, half a cycle, one and a half cycles and two and a half cycles and so on. The way around this is to use your original method to get the approximate delay then switch to the phase method to 'fine tune' the result.
Going back to your code, yes, the while(1) will now work although you don't need to include all the main() function inside it, the part that sets up the registers doesn't need to be repeated. Where your original code failed was that it sat in a tight loop repeating only the while(1) instruction. Yes, the interrupt would still have been processed but it would return back to the while() loop when it completed so there was nowhere a fresh PWM signal could be generated. Remember you were looking for the delay between the start of the 40KHz being sent and it arriving back to cause the interrupt so each time you took a measurement it was necessary to turn off the PWM in order to create a new 'front edge' for it to detect again.
Incidentally, I can't see any decoupling capacitors on your circuit boards, you should fit several capacitors (10uF and 0.1uF) across the ground and supply connections to ensure the PIC and amplifiers work reliably.
Brian.
#include <p18f2520.h> //MCU IN USE
#include <string.h> //???
#include <timers.h> //???
#include <stdlib.h> //???
#include <pwm.h> //INCLUDE PWM TIMER
#include <usart.h>
int channel_one;
char hundreds[11]={'0','1','2','3','4','5','6','7','8','9','T'};
char tens[10]={'0','1','2','3','4','5','6','7','8','9'};
char no[10]={'0','1','2','3','4','5','6','7','8','9'};
int flag=0;
int result1=0;
void high_isr(void); // High priority interrupt service routine
#pragma code high_vector=0x08 // High priority interrupt vector
void high_vector(void)
{
_asm goto high_isr _endasm //JUMP TO INTERRUPT ROUTINE
}
#pragma code //RETURN TO DEFAULT CODE SECTION
#pragma interrupt high_isr
void high_isr(void) // high Priority Interrupt Routine
{
PORTBbits.RB2=!PORTBbits.RB2; //toggle LED
T0CONbits.TMR0ON =0; //STOP COUNTER
result1 = ReadTimer0(); //READ VALUE OF COUNTER
while (BusyUSART()); // ensure the serial port is not busy
WriteUSART('s');
while (BusyUSART());
WriteUSART(hundreds[(result1/100)]);
while (BusyUSART());
WriteUSART(tens[(result1%100)/10]);
while (BusyUSART());
WriteUSART(no[(result1%100)%10]);
SetDCPWM1(0); //Disable PWM
TMR0L=0b00000000; //TIMER0 STARTING BITS AT 0
TMR0H=0b00000000; //TIMER0 STARTING BITS AT 0
INTCONbits.INT0IF =0; //The INT0 external interrupt CLEARED.
flag=1;
}
void main()
{
result1=0;
result2=0;
TRISA= 0b11111111; // I/O SETTINGS
TRISB= 0b00000011; // I/O SETTINGS
TRISC= 0b10000000; //RC7(R-X) as input & RC6(TX) as output
PORTBbits.RB2=0;
//CONFIGURE AND ACTIVATE INTERNAL OSCILLATOR
OSCCON = 0b01110000; //select internal clock at 8Mhz frequency
OSCTUNE = 0b01000000; // PLL Mode enable, Total Internal Oscillation = 32MHz
//TIMER0 SETTINGS
OpenTimer0 (TIMER_INT_ON & // On Timer0 Interrupt
T0_16BIT & // 16-bits Mode
T0_SOURCE_INT & // External Clock Source
T0_PS_1_1); // Set Prescaler to 1:1
OpenUSART(USART_TX_INT_OFF & // Transmitter Interrupt Off
USART_RX_INT_OFF & // Receiver Interrupt Off
USART_ASYNCH_MODE & // Set USART to Asynchronous Mode
USART_EIGHT_BIT & // 8-bits Data
USART_CONT_RX & // Continuous Reception
USART_BRGH_HIGH,103); // High Speed Rate and Baud Rate = 19200 {(32000000/19200*16)} - 1
//INTERRUPT SETTINGS
INTCON=0b00010000; //DISABLE GLOBAL & ENABLE EXT INTERRUPT, Disables the TMR0 overflow interrupt,
INTCON2=0b01000000; //External Interrupt on RISING edge (BIT6)
RCONbits.IPEN =1; //Enable priority levels on interrupts
INTCONbits.GIEH =1; //Global Interrupt Enable
//TIMER0 START BITS @ 0
TMR0L=0b00000000; //TIMER0 STARTING BITS AT 0
TMR0H=0b00000000; //TIMER0 STARTING BITS AT 0
//THIS IS THE SETTING FOR THE PULSE WIDTH MODULATION
//THIS IS IN PIN 13
SetDCPWM1(400);
OpenPWM1(0xc7);
OpenTimer2(TIMER_INT_OFF & T2_PS_1_1 & T2_POST_1_1); //PRESCALAR IS 1:1
T0CONbits.TMR0ON=1; //START COUNTER!
while(1)
{
if(flag==1)
{
SetDCPWM1(400);
T0CONbits.TMR0ON=1;
}
}
} //END OF MAIN
Hi Brian,
Thanks alot with the suggestion. My teacher said it was a good idea. Currently I am trying to use it. For now, I managed to output the results to the hyper terminal. But the results given were to fast. So my other teacher suggested to take the every 100 results, then only display the average. Atleast the results displayed is slightly slower so I can easily monitor it. But the problem now, is how do I take every 100 result, store, compute the average, and display it, and then clear back the value stored, and start storing new 100 results? I know must use array, but since it is in the interrupt function, I can't put 'do while' in the interrupt function as the cpu needs to clear bits, exit the interrupt func, then wait for another interrupt, take 2nd results. I am headache trying to figure a way out. I hope I don't have to use another interrupt..
This is my updated code
Code:#include <p18f2520.h> //MCU IN USE #include <string.h> //??? #include <timers.h> //??? #include <stdlib.h> //??? #include <pwm.h> //INCLUDE PWM TIMER #include <usart.h> int channel_one; char hundreds[11]={'0','1','2','3','4','5','6','7','8','9','T'}; char tens[10]={'0','1','2','3','4','5','6','7','8','9'}; char no[10]={'0','1','2','3','4','5','6','7','8','9'}; int flag=0; int result1=0; void high_isr(void); // High priority interrupt service routine #pragma code high_vector=0x08 // High priority interrupt vector void high_vector(void) { _asm goto high_isr _endasm //JUMP TO INTERRUPT ROUTINE } #pragma code //RETURN TO DEFAULT CODE SECTION #pragma interrupt high_isr void high_isr(void) // high Priority Interrupt Routine { PORTBbits.RB2=!PORTBbits.RB2; //toggle LED T0CONbits.TMR0ON =0; //STOP COUNTER result1 = ReadTimer0(); //READ VALUE OF COUNTER while (BusyUSART()); // ensure the serial port is not busy WriteUSART('s'); while (BusyUSART()); WriteUSART(hundreds[(result1/100)]); while (BusyUSART()); WriteUSART(tens[(result1%100)/10]); while (BusyUSART()); WriteUSART(no[(result1%100)%10]); SetDCPWM1(0); //Disable PWM TMR0L=0b00000000; //TIMER0 STARTING BITS AT 0 TMR0H=0b00000000; //TIMER0 STARTING BITS AT 0 INTCONbits.INT0IF =0; //The INT0 external interrupt CLEARED. flag=1; } void main() { result1=0; result2=0; TRISA= 0b11111111; // I/O SETTINGS TRISB= 0b00000011; // I/O SETTINGS TRISC= 0b10000000; //RC7(R-X) as input & RC6(TX) as output PORTBbits.RB2=0; //CONFIGURE AND ACTIVATE INTERNAL OSCILLATOR OSCCON = 0b01110000; //select internal clock at 8Mhz frequency OSCTUNE = 0b01000000; // PLL Mode enable, Total Internal Oscillation = 32MHz //TIMER0 SETTINGS OpenTimer0 (TIMER_INT_ON & // On Timer0 Interrupt T0_16BIT & // 16-bits Mode T0_SOURCE_INT & // External Clock Source T0_PS_1_1); // Set Prescaler to 1:1 OpenUSART(USART_TX_INT_OFF & // Transmitter Interrupt Off USART_RX_INT_OFF & // Receiver Interrupt Off USART_ASYNCH_MODE & // Set USART to Asynchronous Mode USART_EIGHT_BIT & // 8-bits Data USART_CONT_RX & // Continuous Reception USART_BRGH_HIGH,103); // High Speed Rate and Baud Rate = 19200 {(32000000/19200*16)} - 1 //INTERRUPT SETTINGS INTCON=0b00010000; //DISABLE GLOBAL & ENABLE EXT INTERRUPT, Disables the TMR0 overflow interrupt, INTCON2=0b01000000; //External Interrupt on RISING edge (BIT6) RCONbits.IPEN =1; //Enable priority levels on interrupts INTCONbits.GIEH =1; //Global Interrupt Enable //TIMER0 START BITS @ 0 TMR0L=0b00000000; //TIMER0 STARTING BITS AT 0 TMR0H=0b00000000; //TIMER0 STARTING BITS AT 0 //THIS IS THE SETTING FOR THE PULSE WIDTH MODULATION //THIS IS IN PIN 13 SetDCPWM1(400); OpenPWM1(0xc7); OpenTimer2(TIMER_INT_OFF & T2_PS_1_1 & T2_POST_1_1); //PRESCALAR IS 1:1 T0CONbits.TMR0ON=1; //START COUNTER! while(1) { if(flag==1) { SetDCPWM1(400); T0CONbits.TMR0ON=1; } } } //END OF MAIN
Hope to hear from you soon. And I don't know who is Neyolight.
Norulshahlam (short name's shahlam)
Question - is Neyolight the same person as Shalam or are you both students on the same course?
Brian.
result += ReadTimer0();
NumberOfReadings++;
if(NumberOfReadings == 100)
{
NumberOfReadings = 0;
<routine to send result/100 to the USART>
}
sprintf(DisplayText,"s%d/n",result/100);
WriteUSART(DisplayText);
Sorry Neyolight, please don't take offense. The name in the thread changed but the topic seemed to stay the same so I wasn't sure who I was replying to.
Shalam, thanks for the video and I 'm sorry I couldn't reply sooner, I have a building company working here at the moment and they keep cutting the electricity off which makes emailing a bit difficult!
The way to take averages is simply to add each reading until you have done it 100 times then set a flag to trigger the display routine. I assume the 'ReadTimer0() is a function in your compiler library that returns a 16-bit value, so declare 'result' as a 'double' or 'long int' to hold the result then use:
Code:result += ReadTimer0(); NumberOfReadings++;
In the main program loop, check if enough readings have been totalled by using:
Code:if(NumberOfReadings == 100) { NumberOfReadings = 0; <routine to send result/100 to the USART> }
Part of your problem is that the USART is itself a timed element, each time a character is sent, it has to wait for it to be clocked out of the TX pin and for the transmit register to be reported as empty. You are doing this inside a the interrupt routine so it causes a relatively long delay and several interrupts may occur while you are reporting the result. As a general rule in all programming, keep your interrupts routines as short as possible because by their nature, they are invoked because something needs immediate attention. Some code is inevitable but if you can do the slower jobs like sending to the serial port in the normal (non-interrupt) part of the program where there is more time to spare, it usually works out better.
I'm not sure your character arrays are necessary, does your compiler have a formatted print function (sprintf or printf) to convert numbers to characters for you? For example, you send 's' followed by the result, could you use something like:
Code:sprintf(DisplayText,"s%d/n",result/100); WriteUSART(DisplayText);
To format the result into a character string 'DisplayText' then send it to the PC. I may not have the exact function names correct for your compiler but there should be something similar, your tutor should be able to help with the function to send a string to the USART.
Brian.
#include <p18f2520.h> //MCU IN USE
#include <string.h>
#include <timers.h>
#include <stdlib.h>
#include <pwm.h> //INCLUDE PWM TIMER
#include <usart.h>
#include <capture.h>
int channel_one;
char tenthousands[10]={'0','1','2','3','4','5','6','7','8','9'};
char thousands[10]={'0','1','2','3','4','5','6','7','8','9'};
char hundreds[10]={'0','1','2','3','4','5','6','7','8','9'};
char tens[10]={'0','1','2','3','4','5','6','7','8','9'};
char no[10]={'0','1','2','3','4','5','6','7','8','9'};
float average,sum, period;
int result=0;
int result_previous=0;
int T;
void high_isr(void); // High priority interrupt service routine
#pragma code high_vector=0x08 // High priority interrupt vector
void high_vector(void)
{
_asm goto high_isr _endasm //JUMP TO INTERRUPT ROUTINE
}
#pragma code //RETURN TO DEFAULT CODE SECTION
#pragma interrupt high_isr
void high_isr(void) // high Priority Interrupt Service Routine
{
PIR1bits.CCP1IF=0; //CCP1 INTERRUPT REGISTER CAPTURE OCCURED
PIR2bits.TMR3IF=0; //TIMER3 OVERFLOW OCCURED
if(!CapStatus.Cap1OVF)
result= ReadCapture1(); //READ VALUE OF COUNTER
}
void main(void)
{
INTCONbits.GIEH=0; //DISABLE GLOBAL INT
TRISA= 0b11111111; // I/O SETTINGS
TRISB= 0b00000011; // I/O SETTINGS
TRISC= 0b10000100; //RC7(R-X) as input & RC6(TX) as output
//RC2=INPUT
//CONFIGURE AND ACTIVATE INTERNAL OSCILLATOR
OSCCON = 0b01110000; //select internal clock at 8Mhz frequency
OSCTUNE = 0b01000000; // PLL Mode enable, Total Internal Oscillation = 32MHz
// Configure Capture1
OpenCapture1( C1_EVERY_RISE_EDGE &
CAPTURE_INT_ON );
// Configure Timer3
OpenTimer3(TIMER_INT_ON &
T3_16BIT_RW &
T3_SOURCE_INT &
T3_PS_1_8 &
T3_OSC1EN_ON &
T3_SYNC_EXT_ON &
T3_SOURCE_CCP );
OpenUSART(USART_TX_INT_OFF& // Transmitter Interrupt Off
USART_RX_INT_OFF & // Receiver Interrupt Off
USART_ASYNCH_MODE & // Set USART to Asynchronous Mode
USART_EIGHT_BIT & // 8-bits Data
USART_CONT_RX & // Continuous Reception
USART_BRGH_HIGH,103); // High Speed Rate and Baud Rate = 19200 {(32000000/19200*16)} - 1
//INTERRUPT SETTINGS
RCONbits.IPEN=1; //ENABLE PRIORITY INT
IPR1bits.CCP1IP=1; //HIGH PRIORITY BIT
INTCONbits.GIEH=1; //ENABLE GLOBAL INT
PIE1bits.CCP1IE=1; //ENABLE CCP1 INT
while(1)
{
if (PIR1bits.CCP1IF==0) //IF CAPTURE OCCURED,
{
PORTBbits.RB2=!PORTBbits.RB2;
result_previous=result;
T = result-result_previous;
while (BusyUSART()); // ensure the serial port is not busy
WriteUSART(' '); //sent data to hyper terminal link thru com1
while (BusyUSART()); // ensure the serial port is not busy
WriteUSART(hundreds[(T/100)]); //sent data to hyper terminal link thru com1
while (BusyUSART()); // ensure the serial port is not busy
WriteUSART(tens[(T%100)/10]); //sent data to hyper terminal link thru com1
while (BusyUSART()); // ensure the serial port is not busy
WriteUSART(no[(T%100)%10]); //sent data to hyper terminal link thru com1
while (BusyUSART()); // ensure the serial port is not busy
WriteUSART(' '); //sent data to hyper terminal link thru com1
if(PIR2bits.TMR3IF==0) //IF TIMER3 OVERFLOWS, RESET IT
TMR0L=0b00000000;
TMR0H=0b00000000;
}
}
}//END OF MAIN
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?