void extrint (void) interrupt 0 // external Interrupt to detect the heart pulse
{
bt = tick; // number of ticks are picked
tick = 0; // reset for next counting
}
void timer0 (void) interrupt 1 using 1 // Timer 0 for one second time
{
TH0 = 0xdc; // The value is taken for Ssc/100 at crystal 11.0592MHz
sec100++; // It is incremented every Ssc/100 at crystal 11.0592MHz
tick++; // This variable counts the time period of incoming pulse in Sec/100
if (tick >= 3500)
{tick = 0;} // tick are limited to less than 255 for valid calculation
if (sec100 >= 100) // 1 sec = sec100 * 100
{
sec++;
sec100=0;
}
}
Can somebody explain me what the above code means and does. It was written for a 8051 microcontroller.
i got it from here
http://www.zembedded.com/heart-rate-beats-meter-with-microcontroller-at89c51-based-heartbeat-monitor/
Very hard to tell without context. I guess following:
The timer0 interrupt routine is called every 100th of a second. There it increments the tick counter which is reset to 0 as soon as it gets bigger than 3500. The sec counter seems to be a second counter as it is incremented every 100th call to timer0 (which is called 100 times per second).
The extrint seems to be called upon some external event. It just copies the actual value of tick into bt (presumably for some further processing) and resets tick to 0.
Related
I am currently working with S32k142 microcontroller.
I would like to configure a 1ms delay using the RTC clock. I have an external RTC clock(32.768KHz) which has been configured to drive the RTC module of the microcontroller.
I have programmed the following:
void wait_1ms_RTC(void)
{
UINT32 tpr = (UINT32)RTC->TPR; // RTC Time Prescaler Register: increments at a freq of 32.768KHz
UINT32 tsr = (UINT32)RTC->TSR; // RTC Time Seconds Register: increments every second
tpr = tpr + (UINT32)32; // 32->1ms(32*30.51us=976.32us)
if (tpr <= 32767)
{
while (((UINT32)RTC->TPR <= tpr)&& ((UINT32)RTC->TSR <= tsr));
}
else
{
while (((UINT32)RTC->TPR <= (tpr - 32768))&& ((UINT32)RTC->TSR <= tsr+1));
}
}
This code simply reads the TPR and TSR register, and waits till the TPR register and TSR register reached certain value that corresponds to 1ms.
This works most of the time except in few occasions where it does not create a delay of 1ms ,I am assuming it is happening during the roll over, but still cannot figure out where exactly is the issue in the code.
Any ideas on how this can be solved?
You have over complicated it; you only need the TPR. By shifting the TPR value left by 1 bit, and assigning it to uint16_t, the natural modulo 216 arithmetic deals with the roll-over for you:
#define RTC_TPR_MILLISEC ((32768<<1)/1000)
void wait_1ms_RTC(void)
{
// RTC Time Prescaler Register: 0 to 2^15,
// shift-left 1 but to make it 2^16 so uint16_t modulo arithmetic works
uint16_t start = RTC->TPR << 1 ;
while( (RTC->TPR << 1) - start < RTC_TPR_MILLISEC )
{
// spin
}
}
It fact it is probably even simpler than that. The user manual shows that TPR is a 16 bit register and that TSR is incremented when TPR:14 transitions from 1 to 0. It does not imply that TPR is a 15 bit value and that the counter is reset to zero after 32767. I am not familiar with the part, but if in fact it is a full 16 bit counter as the documentation suggests then the shifting is unnecessary:
#define RTC_TPR_MILLISEC (32768/1000)
void wait_1ms_RTC(void)
{
// RTC Time Prescaler Register: 0 to 2^16
uint16_t start = RTC->TPR ;
while( RTC->TPR - start < RTC_TPR_MILLISEC )
{
// spin
}
}
If you are not sure why that works, see How to deal with a wrapping counter in embedded C (the example there is a 32 bit counter, but the same applies for 16 bit).
I cant see how the following code dmaking a delay?
We have SysTick iterrupt which i dont know what it means.
What is the meaning of SysTick_Config(CMU_ClockFreqGet(cmuClock_CORE)?
Thanks.
#include <stdint.h>
#include <stdbool.h>
#include "em_device.h"
#include "em_chip.h"
#include "em_cmu.h"
#include "em_emu.h"
#include "bsp.h"
#include "bsp_trace.h"
void SysTick_Handler(void)
{
msTicks++; /* increment counter necessary in Delay()*/
}
void Delay(uint32_t dlyTicks)
{
uint32_t curTicks;
curTicks = msTicks;
while ((msTicks - curTicks) < dlyTicks) ;
}
int main(void)
{
/* Chip errata */
CHIP_Init();
CMU_ClockEnable(cmuClock_GPIO,true);
/* Setup SysTick Timer for 1 msec interrupts */
if (SysTick_Config(CMU_ClockFreqGet(cmuClock_CORE) / 1000)) {
while (1) ;
}
}
The EFM32 is an ARM Cortex-M based device which has a hardware timer/counter called SYSTICK. SYSTICK increments at a rate related to the core clock frequency of the processor, in this case that frequency in counts-per-second is returned by CMU_ClockFreqGet(cmuClock_CORE).
The reload value of SYSTICK can be set, here that is done by SysTick_Config(). When the count reaches zero an interrupt is generated and the counter is reloaded. Here by setting the count to the SYSTICK frequency divided by 1000, you will get an interrupt every one millisecond.
An interrupt causes an associated handler to be called asynchronously to the normal code flow (the while loop in main in this case). So here SysTick_Handler() is called every 1 ms, incrementing msTicks (a count of elapsed milliseconds).
The Delay() function polls msTicks until dlyTicks have elapsed. curTicks is a snapshot of the value of msTicks at the start of the delay, the expression (msTicks - curTicks) < dlyTicks therefore becomes false after dlyTicks milliseconds (actually may be up-to 1ms less because msTicks is incremented asynchronously to anyDelay() call).
SysTick is the short name for System Timer. It's a timer generating a periodic interrupt. If the interrupt occurs, SysTick_Handler is called. In increases the variable msTicks by 1. Since the timer is configured to interrupt every millisecond (more about it later), msTicks represents the number of milliseconds since the microcontroller started.
Delay takes the current value of msTicks and loops (waits) until it has reached the initial value plus dlyTicks. The math in the function might look strange. But it's the proper way to do it overflow-safe.
SysTick_Config configures how frequently the system timer interrupt is trigger. This function takes the number of clock cycle as the period between interrupts. To make the period 1ms, the CPU core clock frequency (CMU_ClockFreqGet(cmuClock_CORE)) must be divided by 1000.
I'm trying to generate note for example Do , do's frequency is 523.
I wrote some codes but, i did not work
Systick 8 mhz
void note1(void){ // Note Do
for (int i = 0; i < 523; i++){
GPIOE->ODR = 0x4000;
delay_ms(1);
GPIOE->ODR = 0x0000;
delay_ms(1);
}
}
How can we solve this problem ?
EasyMx Pro v7
I'm calling the function like that
void button_handler(void)
{
note1();
// Clear pending bit depending on which one is pending
if (EXTI->PR & (1 << 0)){
EXTI->PR = (1 << 0);
}
else if (EXTI->PR & (1 << 1)){
EXTI->PR = (1 << 1);
}
}
523 times sending 1 and 0 and delay_ms 1 = 1 ms
1000 = 1 sec
On STM32 (as I can see you have it) you have timers which can be configured as PWM output.
So use timer, set period and prescaler values according to your needed frequency and set duty cycle on channel to 50%.
If you need 523Hz PWM output, then set your timer PWM to 523Hz using prescaler and period value:
timer_overflow_frequency = timer_input_clock /
(prescaler_value + 1) /
(period_value + 1) ;
Then, for your output channel set value half of timer period value.
For standard peripheral library, tutorial can be used from here:
https://stm32f4-discovery.net/2014/05/stm32f4-stm32f429-discovery-pwm-tutorial/
Link from unwind for Cube https://electronics.stackexchange.com/questions/179546/getting-pwm-to-work-on-stm32f4-using-sts-hal-libraries
You appear to have a fundamental misunderstanding. In your code note1(), the value 523 will affect only the duration of the note, nit its frequency. With 1ms high, 1ms low repeated 523 times you will generate a tone of approximately 500Hz for approximately 1.43 seconds. I say "approximately" because there will be some small overhead in the loop other then the time delays.
A time delay resolution 1ms is insufficient to generate an accurate tone in that manner. To do it in the manner you have, each delay would need to be 1/2f seconds, so for 523Hz approximately 956ms. The loop iteration count would need to be ft, so for say .25 seconds, 131 iterations.
However if button_handler() is as it appears to be an interrupt handler, you really should not be spending 1.46 seconds in an interrupt handler!
In any event this is an extraordinarily laborious, CPU intensive and inaccurate method of generating a specific frequency. The STM32 on your board is well endowed with hardware timers with direct GPIO output that will generate the frequency you need accurately with zero software over head. Even if none of the timers map to a suitable GPIO output that you need to use, ou can still get one to generate an interrupt at 1/2f and toggle the pin in the interrupt handler. Either way that will leave the processor free to do useful stuff while the tone is being output.
(I'll gladly post code if someone can point out how to paste it in here without using the 4 space indentation system that doesn't work)
Hello folks
After ~9Hours racking by brains, I can't find an answer or find where my calculations are going wrong... but they are.
I have a circuit built using a microchip 18F2550 microcontroller.
I am using this circuit to measure the delay between 2 signals and am using the 2 CCP registers in capture mode.
This all works and the result is sent to the PC (over USB serial) all dandy, but the results are wrong.
I have to apply a gain of ~16000 to any results to get somewhere near the delay presented to the pins.
I have the delay set in the line
Timer1 is set as an internal
Timer3 is disabled
relevant interrupts are enabled
and the main routine runs continuously.
When I get a rising edge detection on the CCP1 pin, the interrupt is configured to reset timer1 to zero as well as the overflow counter
#INT_CCP1
void ccp1_isr() // Captures the rising edge of CCP1 pin.
{
if(timing==FALSE){ // only do this on the edge, any bouncing will reset timers etc.
set_timer1(0);
T1_Overflow = 0;
Pulse_Time = 0;
timing = 1; // Set flag to indicate timing.
output_high(BLUE_LED);
}
}
the timing flag ensures the times cannot be reset by another pulse on the CCP1 pin.
Timer1 should then be reset and start counting as normal. Every time it rolls around by 65535 (16bit device) another interrupt is fired after which the amount of overflows are incremented.
#INT_TIMER1
void isr()
{
T1_Overflow++;
}
Finally, when the input pin on CCP2 goes high, the CCP_2 interrupt is triggered. This captures the value of the CCP register (which is the value of Timer0 at the time the interrupt was fired) and the overflow register.
#INT_CCP2
void ccp2_isr()
{
if(timing == TRUE){ // only output this when preceded by CCP1
if(Count_Done == FALSE) // do this once only
{
Count_Done = TRUE; // and also flag to the main routine to output data to the terminal.
Pulse_time = CCP_2;
Pulse_Overflow = T1_Overflow;
measureCount++; // increment the number of measures.
}
output_low(BLUE_LED);
timing = FALSE;
}
}
CCP1 can now start responding to the inputs again.
The idea of this is that every time I get a pulse of one input at CCP1 followed by CCP2, a string is sent to the terminal with a counter, the number of overflows and the time left in the timer.
while(TRUE) // do forever while connected
{
usb_task(); // keep usb alive
if(Count_Done == TRUE)
{
printf(usb_cdc_putc, "%lu , %lu , %lu \r\n",measureCount, pulse_time, pulse_overflow);
Count_Done = FALSE;
}
so, I should get an output to the terminal of something like "1,61553,35" for a ~12ms delay between CCP1 and CCP2.
The problem is that these are the results I am getting for a 200ms pulse provided to the circuit. (Verified twice)
so where am I going wrong.
I have a 48MHZ Clock with no prescaler which implies a cycle every 20ns.
Divide by for 4 instructions per cycle for the clock which implies 5.2ns every cycle
16 bit timer which implies rollover every 65535*5.2ns = 341us per rollover.
when you do the calculations (0.000341*pulse_overflow)+pulse_time*(5.2*(10^-9))
then the above data gives 0012.27ms and not the 200ms provided.
Can anyone point out where I am going wrong with these calculations???
Your error is in "Divide by for 4 instructions per cycle for the clock which implies 5.2ns every cycle"
The counter ticks once every 4 cycles, not 4 times per cycle. So, the correct calculations are:
2.08333E-08 s/cycle of osc
8.33333E-08 s/tick of timer
0.005461333 s/rollover
You are off by a factor of 16.
I am having a hard time understanding some code I found for using a timer and interrupts on an ARM board I have. The timer basically toggles an LED every interrupt between on and off to make it flash.
void main(void) {
/* Pin direction */
led_init();
/* timer setup */
/* CTRL */
#define COUNT_MODE 1 /* Use rising edge of primary source */
#define PRIME_SRC 0xf /* Peripheral clock with 128 prescale (for 24 MHz = 187500 Hz)*/
#define SEC_SRC 0 /* Don't need this */
#define ONCE 0 /* Keep counting */
#define LEN 1 /* Count until compare then reload with value in LOAD */
#define DIR 0 /* Count up */
#define CO_INIT 0 /* Other counters cannot force a re-initialization of this counter */
#define OUT_MODE 0 /* OFLAG is asserted while counter is active */
*TMR_ENBL = 0; /* TMRS reset to enabled */
*TMR0_SCTRL = 0;
*TMR0_CSCTRL = 0x0040;
*TMR0_LOAD = 0; /* Reload to zero */
*TMR0_COMP_UP = 18750; /* Trigger a reload at the end */
*TMR0_CMPLD1 = 18750; /* Compare one triggered reload level, 10 Hz maybe? */
*TMR0_CNTR = 0; /* Reset count register */
*TMR0_CTRL = (COUNT_MODE<<13) |
(PRIME_SRC<<9) |
(SEC_SRC<<7) |
(ONCE<<6) |
(LEN<<5) |
(DIR<<4) |
(CO_INIT<<3) |
(OUT_MODE);
*TMR_ENBL = 0xf; /* Enable all the timers --- why not? */
led_on();
enable_irq(TMR);
while(1) {
/* Sit here and let the interrupts do the work */
continue;
};
}
Right now, the LED flashes at a rate that I cannot determine per second. I'd like it to flash once per second. However, I do not understand the whole comparison and reloading.
Could somebody better explain this code?
As timers are a vendor- and part-specific feature (not a part of the ARM architecture), I can only give general guidance unless you mention which CPU or microcontroller you are dealing with.
Timers have several features:
A size, for instance 16 bits, which means they can count up or down to/from 65535.
A clock input, given as a clock frequency (perhaps from the CPU clock or an external crystal), and a prescaler which divides this clock frequency to another value (or divide by 1).
An interrupt on overflow - when the timer wraps back to 0, there is usually an option to trigger an interrupt.
A compare interrupt - when the timer meets a set value it will issue an interrupt.
In your case, I can see that you are using the compare feature of your timer. By determining your timer clock input, and calculating new values for the prescalers and compare register, you should be able to achieve a 1 Hz rate.
Before trying to understand the code you found, please do understand how a Timer Peripheral Unit works, then understand how you can configure it's registers to get the desired output.
How a Timer Peripheral Unit works?
This is hardware module which is embedded into micro controller along with CPU and other peripherals. Every peripheral modules inside micro controller are synchronized with common clock source. With reference to the code, Timer peripheral clock is 24 MHz which is then pre-scaled by 128 which means it will work at 187500 Hz. Now this frequency will depend upon clock configuration and oscillator.
Now Timer unit has a counter register which can count up to it's bit-size which could be 8,16 or 32 generally. Once you enable counting, this counter starts up-counting or down-counting the rising or falling or on both edges. Now you have choices whether you want to up-count (from 0 towards 255, for 8-bit) or down count (from 255 towards 0) and you want to count on which clock edge.
Now, at 187500 Hz, 1 cycle = 5.333333 us, if you are counting once in 1 cycle either at rising or at falling edge and e.g, if counter value = 100 (Up counting), total time elapsed is 5.33333*100=533us. Now you have to set a compare value value for the counter to set this period which will depend upon your flash rate. This compare value will be compared against your counter value in by comparator of Timer and Once it matches it will send an interrupt signal if you have enabled interrupt generation on compare match, where you can toggle you LED.
I hope you have understood How a Timer works.
In your sample code, Timer is configured to obtain a compare match event at the rate of 10Hz. so compare value is 187500/10 = 18750., for 1sec you can keep it 187500/1.
you have Timer Control Register TMR0_CTRL, where you can configure whether you want to count up or down, count on falling/rising/both edges, count only once/continuous, count upto compare value and then reset or keep counting till it's limit. Refer to micro controller manual for details of each bit fields.