Produce tones at certain time-interval using C programming - c

Im using C language for a PIC18F to produce tones such that each of them plays at certain time-interval. I used PWM to produce a tone. But I don't know how to create the intervals. Here is my attempt.
#pragma code //
void main (void)
{
int i=0;
// set internal oscillator to 1MHz
//OSCCON = 0b10110110; // IRCFx = 101
//OSCTUNEbits.PLLEN = 0; //PLL disabled
TRISDbits.TRISD7 = 0;
T2CON = 0b00000101; //timer2 on
PR2 = 240;
CCPR1L = 0x78;
CCP1CON= 0b01001100;
LATDbits.LATD7=0;
Delay1KTCYx(1000);
while(1);
}

When I'm doing embedded programming, I find it extremely useful to add comments explaining exactly what I'm intending when I'm set configuration registers. That way I don't have to go back to the data sheets to figure out what 0x01001010 does when I'm trying to grok the code the next time I have to change it. (Just be sure to keep the comments in sync with the changes).
From what I can decode, it looks like you've got the PWM registers set up, but no way to change the frequency at your desired intervals. There are a few ways to do it, here are 2 ideas:
You could read a timer on startup, add the desired interval to get a target time, and poll the timer in the while loop. When the timer hits the target, set a new PWM duty cycle, and add the next interval to your target time. This will work fine, until you need to start doing other things in the background loop.
You could set timer0's count to 0xFFFF-interval, and set it to interrupt on rollover. In the ISR, set the new PWM duty cycle, and reset timer0 count to the next interval.
One common way of controlling timing in embedded processes looks like this:
int flag=0;
void main()
{
setup_interrupt(); //schedule interrupt for desired time.
while (1)
{
if (flag)
{
update_something();
flag = 0;
}
}
Where does flag get set? In the interrupt handler:
void InterruptHandler()
{
flag = 1;
acknowledge_interupt_reg = 0;
}
You've got all the pieces in your example, you just need to put them together in the right places. In your case, update_something() would update the PWM. The logic would look like: "If it's on, turn it off; else turn it on. Update the tone (duty cycle) if desired"
There should be no need for additional delays or pauses in the main while loop. The goal is that it just runs over and over again, waiting for something to do. If the program needs to do something else at a different rate, you can add another flag, which is triggered completely independently, and the timing of the two tasks won't interfere with each other.

EDIT:
I'm now confused about what you are trying to accomplish. Do you want a series of pulses of the same tone (on-off-on-off)? Or do you want a series of different notes without pauses (do-re-me-fa-...)? I had been assuming the latter, but now I'm not sure.
After seeing your updated code, I'm not sure exactly how your system is configured, so I'm just going to ask some questions I hope are helpful.
Is the PWM part working? Do you get the initial tone? I'm assuming yes.
Does your hardware have some sort of clock pulse hooked up to the RA4/T0CKI pin? If not, you need T0 to be clock mode, not counter mode.
Is the interrupt being called? You are setting INT0IE, which enables the external interrupt, not the timer interrupt
What interval do you want between tone updates? Right now, you are getting 0xFFFF / (clock_freq/8) You need to set the TMR0H/L registers if you want something different.
What's on LATD7? and why are you clearing it? Are you saying it enables PWM output?
Why the call to Delay()? The timer itself should be providing the needed delay. There seems to be a disconnect about how to do timing. I'll expand my other answer
Where are you trying to change the PWM frequency? Don't you need to write to PR2? You will need to give it a different value for every different tone.
"Halting build on first failure as requested."
This just says you have some syntax error, without showing us the error report, we can't really help.

In Windows you can use the Beep function in kernel32:
[DllImport("kernel32.dll")]
private static extern bool Beep(int frequency, int duration);

Related

Easy way to increment a demux without calling each pin every time?

I need to increment through 2 demultiplexers. Right this moment I have it set up to where every time it just enables those specific pins as the output. I have been trying to wrap my head around an easy way to increment this in a function and or being able to call specific outputs? Or would the only way really would be to have a function called void trigger(int output) and have a switch statement within it for each of the 16 outputs and their associated pin triggers.
Increment the outputs through the various inputs. They are currently being used to drive a set of LEDs.
transformer(dv_out, 0); //recharge transformer
module_0_SetHigh();
module_1_SetHigh();
if (!sec) {
demux0_SetHigh();
demux0_SetLow();
}
if (sec) {
demux1_SetHigh();
demux1_SetLow();
}
module_0_SetLow(); //disable pin select
module_1_SetLow();

Stm32 PWM sampling

I have a timer set up in the cube to make a PWM... Just setting ARR and CCR to different values.
I'm using the callback functions for both events that HAL set up for me, I think one is for the CCR compare event and the other is for the ARR compare event.
Anyway, in both of those I'm toggling a GPIO port like this:
GPIOC->ODR = foo;
Anyway, I want to sample the values of 3 ADC1 channels during the high pulse, but I'm not sure how to do that accurately. I'm using DMA in circular mode with the ADC1 right now.
I don't want to sample immediately after setting the pins, because there's propagation delay, noise, etc.
So, I want to:
Set the pins, wait a very short and constant amount of time, sample all the channels and then do some math on the results.
This is for a Bldc motor controller, by the way... Im trying to sample the BEMF on the positive side of the PWM drive signal, and I'm driving it at 18khz, 5% duty cycle, so my pulse lasts for 2.7us.
I'm not sure how to handle or debug this because it's so timing related and I need the motor to deliver the signal that I'm using... If the motor isn't spinning, then there's no feedback signal to work on. It sure seems like I'm trying to do too much in the timer ISRs, though.
Sorry I can't post any code right now... Im at the grocery store, but I'll put some up when I get back.

STM32 - TIM2_ETR pin, connected to pin PA0 (button), incrementing the timer in strange way

I am trying to implement PWM LED dimming in 6 stages, where each stage in more bright, based on clicking button, which increments external pin, which serves the value to timer.
I am facing a problem, that sometimes, value variable is too large than it should be and skips some levels of brightness. For example, value increments: 1,2,3, then jumps to 6,7, etc.
Can anybody pinpoint where is the mistake I am making.
Here is the code:
//EDIT: code removed, because it is a school assignment
This looks like contact bouncing. When input is processed by the CPU, a simple way to solve it is to disable input for a certain duration after an event is detected. Since you directly control timer input from a button, you may not have much control. However, I would experiment with the ETF field of the SMCR register (which in your case is likely set by the sClockSourceConfig.ClockFilter field) and the clock divisor CKD of the CR1 register (which seems like htim2.Init.ClockDivision in your code) (sorry, I am not familiar with STM libraries).

Arduino timer within a timer

Arduino Nano and I need a timer within a timer and having some problems getting my head around the logic. I have played with some Libraries on GitHub, Timer, SimpleTimer and Metro but none seem to do what I need. Or, if they can I can't seem to get them to do it.
I need to switch a relay on for about 2-minutes and then off, every hour. I am trying
loop
{ if (millis() - 3600000 > TimeMax)
{ relay(on);
if (millis() - 12000 > relayMax)
TimeMax = millis();
}
}
It doesn't seem to work and I need this to all stay working within the "loop" as I have an nRF24L radio listening.
Could someone please help me with code snippets or at least an outline how to go about this.
Thanks
Ok, first of all timers in embedded dev speak means interrupts that gets fired after a delay. Generally speaking you want interrupts to handle very atomic actions, because you don't want to have an interrupt triggered while another one is triggered, because that could be the scenario of a horror movie.
But why would you want to make something hard, complex and overengineered, when it can be simple?
All you need to do is handle it through a simple dual state machine:
#define OPEN_DELAY 120*1000
#define CLOSE_DELAY 3600*1000
// N.B.: to be precise here, to make 2 minutes every hour,
// CLOSE_DELAY should be 3600*1000-OPEN_DELAY so it
// does not shift by 2 minutes every hour.
void loop() {
static bool open=false;
static long timestamp = millis();
if (!open && millis()-timestamp > CLOSE_DELAY) {
open=true; // change state
timestamp = millis(); // rearm timestamp
set_relay_on();
} else if (open && millis()-timestamp > OPEN_DELAY) {
open=false;
timestamp = millis();
set_relay_off();
}
}
The only reason you might want to use timer would be to save battery by keeping the AVR in sleep mode as much as possible. Then you'd set the timer to the biggest possible value before putting it to sleep, making it wake up the AVR with an interrupt every few seconds or so, so then you run the loop() once in CLOSE state going back to sleep — there you don't need to write an ISR, the main loop() is enough, or keeping it up for the full two minutes in OPEN state.
There's good documentation on timers you might want to read (beware the headaches, though):
http://maxembedded.com/2011/06/introduction-to-avr-timers/
Here's how to put the arduino to sleep for long delays:
http://www.bot-thoughts.com/2013/11/avr-watchdog-as-sleep-delay.html
HTH

Push a button while reading sensor in Arduino

I've been doing a little thermometer project to learn Arduino and there is an annoying thing that I have no idea how to resolve.
I have two push buttons to set Min and Max temperature and when I push the buttons it's supposed to set the Min and Max temperature on display.
The problem is that sometimes (50% of times) when I push the buttons during the reading of the temperature sensor, the buttons don't work. I press it but the Min/Max temperature are not set because Arduino is stuck in reading the temperature sensor.
Is there any trick to solve this kind of problem? If I had a keyboard for typing some number for example I imagine I would have the same problem and It's not "user-friendly".
Here is an example of part of the code I'm using:
#include <OneWire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal.h>
//variables declaration...
void setup() {
sensors.begin();
sensors.getAddress(sensor1, 0);
pinMode(buzzer, OUTPUT);
pinMode(btBuzzer, INPUT);
pinMode(btMin, INPUT);
pinMode(btMax, INPUT);
}
void loop() {
readButtons();
playBuzzer();
readTemperature();
printDisplay();
delay(150);
}
void readButtons(){
if(digitalRead(btBuzzer)){
buzzerOn = !buzzerOn;
}
if(digitalRead(btMin)){
if(tempMin == 69)
tempMin = 59;
else
tempMin++;
}
if(digitalRead(btMax)){
if(tempMax == 75)
tempMax = 63;
else
tempMax++;
}
}
void readTemperature(){
sensors.requestTemperatures();
temperature = sensors.getTempC(sensor1);
}
//lots of other methods
As others have pointed out here, the button press may not happen at the same time as you query the pin with digitalRead(btBuzzer). This type of problem is what so called "interrupts" were invented for, which allow you to respond to events that may occur while you are not monitoring the pin of interest.
For example, the Arduino UNO R3 allow for interrupts on pin 2 and 3. You should look up the reference for attachInterrupt(). The processor will execute a callback function in the event (the "interrupt") that you register for (e.g. the voltage on pin 2 changing from low to high). This means that you will no longer have to call a readButtons() function from your main loop.
Some of the best ways to learn coding exist in how to answer this question.
What I'd like to suggest doing is to try timing your code. Remember that loop() is creating a repeating structure. So we can say things like how long does the computer take to run each loop. When we have an interrupt like a button press how does that effect the iteration through the loop and is it conditional about how to rest the processor (the delay).
The delay is required so as to not do what's called "spin" the processor (have the processor as quickly as it can do a lot of work to accomplish absolutely nothing). However, notice how the code doesn't account for work done changing how long we delay?
Now let's imagine the processor actually can go through that loop more than one time very quickly. Remember delay of only 150 milliseconds isn't a lot of time. So maybe one button press will be enough to set tempMin from 59 to 69 in rapid succession and loop several times over rather than just increasing one number at a time.
What you have here is a chance to learn debugging. First trick is to determine is the loop running too fast or too slow; are you getting desired functionality or not and finally if you can reask the question after you know if it's happening too fast or slow.
For now, I'd recommend taking a look at global variables and finite state machines (i.e. if you're in a state of button press, don't accept any further button presses until you're done with your state and only transition in known ways).

Resources