I am using PIC24FJ128GA204 microcontroller in PIC24F Curiosity Development Board.
The ISR is executed at least once even when the event not happened.
Here is the code:
#include <xc.h>
int Random_mode_condition=0;
void __attribute__((__interrupt__, __shadow__)) _INT1Interrupt(void) {
Random_mode_condition = 44;
_INT1IF = 0;
}
void RC9_Switch_Config() {
_TRISC9 = 1; // Switch input
RPINR0bits.INT1R = 25;
IFS1bits.INT1IF=0;//Clear the interrupt flag
IPC5bits.INT1IP1=1;//Choose a priority
INTCON2bits.INT1EP=0;//rising edge
IEC1bits.INT1IE=1;//enable INT1 interrupt
}
int main() {
LATC=0x0000;
RC9_Switch_Config();
while(1){
if(Random_mode_condition==44){ TRISC=0x0000; LATC=0xffff;}
}
return 0;
}
Random_mode_condition will equal 44 then the if statement will be executed.
Please help
I have to build synthesizer and I am using C for programing my ATmega128A. I need to record the keypads pressed and play them after some time. For keypad press I am using polling in the main.c. For playing the keypads I am using Timer1. Every time when the timer expires I am storing the keypad frequency and increment counter for it. During play, I calculate the duration firstle, then play it for that interval. When I want to play the stored song, it ticks for some time and starts to make a long sound.
Also, I want to make possible to press, record and palay simultanous keypads. Can you suggest some algorithm for this?
main.c
#include <avr/io.h>
#include <avr/interrupt.h>
#include "keypad.h"
unsigned char temp; // to get keyboard input to play a note
unsigned char option; //to choose the embedded music to play
#define DELAY 1000
int main(void)
{
DDRG = 0xff; // To send sound to BUZ speakers (BUZ is connected to PG.4)
DDRD = 0x00; // Make it input, to get corresponding key to play a note
PORTD = 0xff; // All bits are 1s, so no button is pressed in the beginning
sei(); //Set Interrupt flag as enabled in SREG register
option = no_music; //No music is played on startup, this is default mode for free playing
// This loop keeps playing forever, so the main functionality
// of the program is below
DDRB = 0xff;
DDRD = 0x00; //ready for input
while(1)
{
temp = PIND; //store keyboard input for temporary variable
//PORTB = PIND;
switch(temp)
{
case 254: { // if 1st pin of PORTD is pressed
play_note(notes5[0]); // play corresponding note from octave 5 for 200ms
break;
}
case 253: { // if 2nd pin of PORTD is pressed
play_note(notes5[1]);
break;
}
case 251: { // if 3rd pin of PORTD is pressed
play_note(notes5[2]);
break;
}
case 247: { // if 4th pin of PORTD is pressed
play_note(notes5[3]);
break;
}
case 239: { // if 5th pin of PORTD is pressed
play_note(notes5[4]);
break;
}
case 223: { // if 6th pin of PORTD is pressed
play_note(notes5[5]);
break;
}
case 191: { // if 7th pin of PORTD is pressed
play_note(notes5[6]);
break;
}
case 127: {
if(isRecordingEnabled){
disableRecording();
//toggling LED as the sign of playing the record
toggleLED();
custom_delay_ms(DELAY);
toggleLED();
custom_delay_ms(DELAY);
custom_delay_ms(DELAY);
play_record();
}else{
//toggling LED as the sign of record start
toggleLED();
enableRecording();
}
}
}
}
return 0;
}
keypad.c
#include "structs.h"
#include "play.h"
#define F_CPU 16000000UL // 16 MHz
#include <util/delay.h>
#define BUFFER_SIZE 100
struct played_note buffer[BUFFER_SIZE];
int i = 0;
int8_t isRecordingEnabled = 0;
int8_t recordIndex = 0;
int8_t pressedNote;
int8_t isPressed = 0;
int8_t isPlaying = 0;
unsigned int ms_count = 0;
#define INTERVAL 100
#define DELAY_VALUE 0xFF
ISR(TIMER1_COMPA_vect){
// every time when timer0 reaches corresponding frequency,
// invert the output signal for BUZ, so it creates reflection, which leads to sound generation
//check whether the key was pressed because
//when the recording is enabled the interrupt is working make sound
if(isPressed || isPlaying)
PORTG = ~(PORTG);
if(isRecordingEnabled){
if(PIND == DELAY_VALUE)
pressedNote = DELAY_VALUE;
if(i == 0){
buffer[i].note = pressedNote;
buffer[i].counter = 0;
i++;
}else{
if(buffer[i - 1].note == pressedNote){
//the same note is being pressed
buffer[i - 1].counter++;
}else{
buffer[i++].note = pressedNote;
buffer[i].counter = 0;
}
}
}
}
void initTimer1(){
TIMSK = (1 << OCIE1A); //Timer1 Comparator Interrupt is enabled
TCCR1B |= (1 << WGM12) | (1 << CS12); //CTC mode, prescale = 256
}
void stopTimer1(){
TIMSK &= ~(1UL << OCIE1A);
TCCR1A = 0; //stop the timer1
TIFR = (1 << OCF1A); //Clear the timer1 Comparator Match flag
}
void enableRecording(){
isRecordingEnabled = 1;
i = 0;
ms_count = 0;
initTimer1();
}
void disableRecording(){
isRecordingEnabled = 0;
stopTimer1();
}
//Timer1A
void play_note_during(unsigned int note, unsigned int duration){
OCR1A = note;
pressedNote = note;
isPressed = 1;
initTimer1();
custom_delay_ms(duration);
stopTimer1();
isPressed = 0;
}
//Timer1A
void play_note(unsigned int note){
play_note_during(note, INTERVAL);
}
void play_record(){
isPlaying = 1;
recordIndex = 0;
int duration;
while(recordIndex < i){
PORTB = buffer[return].counter << 8;
duration = INTERVAL * buffer[recordIndex].counter;
if(buffer[recordIndex].note == DELAY_VALUE)
custom_delay_ms(duration);
else
play_note_during(buffer[recordIndex].note, duration);
recordIndex++;
}
isPlaying = 0;
}
Further references can be found in the following github repository:
https://github.com/bedilbek/music_simulation
Actually your question about how to record and replay key presses, should be anticipated by another question about how to play several sounds simultaneously.
Now you're using just PWM output with variable frequency. But this allows you to generate only a single wave of a square form. You cannot play two notes (except of using another timer and another PWM output).
Instead of that, I suggest you to use PWM at the highest frequency and apply a RC or LC filters to smooth high-frequency PWM signal into a waveform, and then apply that waveform to the amplifier and to the speaker to make a sound.
Having this approach you make generate different waveforms, mix them together, make them louder or more silent and even apply a "fade-out" effect to make them sound like a piano.
But your question is not about how to generate that kind of wave-forms, so if you want to know you should start another question.
So, returning to your question.
Instead of having single procedure, which is starting note, holding a pause and only then returning back; I suggest you to have a several procedures, one play_note(note) - which will start playing a note and returns immediately (while note continue playing). And, of course, stop_note(note) - which will stop specified note, if it is played. Also I suggest you to pass a note number, rather than frequency or timer period to the play function. Let's assume 0 is the lowest possible note (e.g. C2), and then they go sequentially by semitones: 1 - C#2, 2 - D2, .... 11 - B2, 12 - C3 ... etc.
For the first time, you may remake your single-note playing procedures to match that.
// #include <avr/pgmspace.h> to store tables in the flash memory
PROGMEM uint16_t const note_ocr_table[] = {
OCR1A_VALUE_FOR_C2, OCR1A_VALUE_FOR_C2_SHARP, ... etc
}; // a table to map note number into OCR1A value
#define NOTE_NONE 0xFF
static uint8_t current_note = NOTE_NONE;
void play_note(uint8_t note) {
if (note >= (sizeof(note_ocr_table) / sizeof(note_ocr_table[0])) return; // do nothing on the wrong parameter;
uint16_t ocr1a_val = pgm_read_word(¬e_ocr_table[note]);
TIMSK = (1 << OCIE1A); //Timer1 Comparator Interrupt is enabled // why you need this? May be you want to use just inverting OC1A output?
TCCR1B |= (1 << WGM12) | (1 << CS12); //CTC mode, prescale = 256 // you may want to use lesser prescalers and higher OCR1A values ?
OCR1A = ocr1a_val;
if (TCNT1 >= ocr1a_val) TCNT1 = 0; // do not miss the compare match when ORC1A is changed to lower values;
current_note = note;
}
void stop_note(uint8_t note) {
if (note == current_note) { // ignore stop for non-current note.
TIMSK &= ~(1UL << OCIE1A);
TCCR1A = 0; //stop the timer1
TIFR = (1 << OCF1A); //Clear the timer1 Comparator Match flag
current_note = NOTE_NONE; // No note is playing
}
}
so, now your task is very simple: you should just pull the state of the keys periodically, let's say 61 times per second (based on the some 8-bit timer with 1:1024 prescaler overflow), and they to note: which keys are changed their state. If some key is pressed, you call play_note to start coressponding note. If the key is released, you call stop_note, also you're counting how many timer cycles passed since the last event.
When recording, you just push those events into array "key X is pressed" or "key X is released" or "X timer cycles expired".
When playing back, you just performing a backward process, scaning your array, and executing commands: calling play_note, stop_note, or waiting exact amount of timer cycles, if it is a pause.
Instead of writing giant switch statement, you may also use a table to scan the buttons
// number of element in the port-state arrays
#define A 0
#define B 1
#define C 2
#define D 3
#define E 4
#define F 5
typedef struct {
port_index uint8_t;
mask uint8_t;
} KeyLocation;
PROGMEM KeyLocation const key_location[] = {
{ B, (1 << 1) }, // where C2 is located, e.g. PB1
{ E, (1 << 3) }, // where C#2 is located, e.g. PE3
...
}
uint16_t ticks_from_prev_event = 0;
uint8_t port_state_prev[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0XFF};
for (;;) { // main loop
wait_tick_timer_to_overflow();
// latching state of the pins
uint8_t port_state[6] = {PINA, PINB, PINC, PIND, PINE, PINF};
for (uint8_t i = 0 ; i < (sizeof(key_location) / sizeof(key_location[0])) ; i++) {
uint8_t port_idx = pgm_read_byte(&key_location[i].port_index);
uint8_t mask = pgm_read_byte(&key_location[i].mask);
if ((port_state[port_idx] & mask) != (port_state_prev[port_idx] & mask)) { // if pin state was changed
if (is_recording && (ticks_from_prev_event > 0)) {
put_into_record_pause(ticks_from_prev_event); // implement it on your own
}
if ((port_state[port_idx] & mask) == 0) { // key is pressed
play_note(i);
if (is_recording) {
put_into_record_play_note(i); // implement
}
} else { // key is released
stop_note(i);
if (is_recording) {
put_into_record_stop_note(i); // implement
}
}
}
}
// the current state of the pins now becomes a previous
for (uint8_t i = 0 ; i < (sizeof(port_state) / sizeof(port_state[0])) ; i++) {
port_state_prev[i] = port_state[i];
}
if (ticks_from_prev_event < 65535) ticks_from_prev_event++;
}
put_into_record_... implement as you wish.
the playback would be the same simple (below just the template, you'll suggest from the function name what they should do)
while (has_more_data_in_the_recording()) {
if (next_is_play()) {
play_note(get_note_from_recording())
} else if (next_is_stop()) {
play_note(get_note_from_recording())
} else {
uint16_t pause = get_pause_value_from_recording();
while (pause > 0) {
pause--;
wait_tick_timer_to_overflow();
}
}
}
This approach gives you two benefits:
1) It doesn't matter how many notes the playing module can play, the keys are recorder while they are pressed and released, so, all simultaneous keys will be recorded and replayed in the same time.
2) It doesn't matter how many notes are pressed in exact the same moment. Since pause and key events are recorded separately, during the replay all the same-time key presses will be replayed in the same time, without an "arpeggio" effect
I am trying to program PIC16F887 and having this interesting problem. I expect from LED to blink one-time and stop forever, however it starts back and never stops although watchdog is disabled. Here is the code. Thanks in advance.
I wrote this in MPLAB v8.84 and programmed using PICkit2 and Hi-Tech C compiler.
#include <htc.h>
#include <pic.h>
#define _XTAL_FREQ 800000
//__CONFIG(0x3FF5);
//functions
void INITgeneral(void);
void ledshow (void);
void main(void) {
INITgeneral();
ledshow();
return;
}
void INITgeneral(void)
{
TRISA = 0;
TRISB = 0;
TRISC = 0;
TRISD = 0;
TRISE = 0;
PORTA = 0;
PORTB = 0;
PORTC = 0;
PORTD = 0;
PORTE = 0;
}
void ledshow(void)
{
__delay_ms(400);
RD0 = 1;
__delay_ms(400);
RD0 = 0;
}
The built-in simulator is very helpful in finding issues such as this one, well worth learning about.
Under the ‘View’ tab select ‘Disassembly Listing’. Notice that the next instruction after returning from the call to ledshow() is the instruction GOTO 0 which loads the program counter with zero, the reset vector. This is why you are endlessly executing the program.
To stop this behavior replace return in main() with an endless loop while(1){};
I'm trying to implement the Dallas OneWire protocol, but I'm having trouble generating a microsecond delay on the STM32l-Discovery.
How do I implement a timer accurate enough to delay the program for x microseconds?
For start I must tell you that there is no way to accomplish a precise usec delay using software. Even if you use an interrupt based system you will have latencies. Off course you can achieve a better accuracy with a larger CPU frequencies.
In order to connect with a 1-Wire device you can use:
A external interface like DS2482-100
A software 1-wire implementation using pin polling.
For the second solution you have to call a software based delay. You can make a flag polling delay or an interrupt based flag polling delay. In both cases you will be sure that a certain amount of time has passed but you can not be sure how match more time has passed. This is because of the CPU latency, the CPU clock etc...
For example consider the following implementation. We program a HW TIMER to continuously count up and we check TIMER's value. We name "jiffy" the time between each TIMER's ticks and jiffies the TIMERS max value:
Low level driver part (ex: driver.h)
// ...
#define JF_TIM_VALUE (TIM7->CNT)
int JF_setfreq (uint32_t jf_freq, uint32_t jiffies);
// ...
Low level driver part (ex: driver.c)
// ...
#include <stm32l1xx.h>
#include <misc.h>
#include <stm32l1xx_rcc.h>
#include <stm32l1xx_tim.h>
/*
* Time base configuration using the TIM7
* \param jf_freq The TIMER's frequency
* \param jiffies The TIMER's max count value
*/
int JF_setfreq (uint32_t jf_freq, uint32_t jiffies) {
uint32_t psc=0;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
SystemCoreClockUpdate ();
if (jf_freq)
psc = (SystemCoreClock / jf_freq) - 1;
if (psc < 0xFFFF) TIM7->PSC = psc;
else return 1;
if (jiffies < 0xFFFF) TIM7->ARR = jiffies;
else return 1;
TIM7->CR1 |= TIM_CR1_CEN;
return 0;
}
// ...
Middleware jiffy system with some delay implementations
jiffy.h:
#include "string.h"
typedef int32_t jiffy_t; // Jiffy type 4 byte integer
typedef int (*jf_setfreq_pt) (uint32_t, uint32_t); //Pointer to setfreq function
typedef volatile struct {
jf_setfreq_pt setfreq; // Pointer to driver's timer set freq function
jiffy_t *value; // Pointer to timers current value
uint32_t freq; // timer's frequency
uint32_t jiffies; // jiffies max value (timer's max value)
jiffy_t jpus; // Variable for the delay function
}jf_t;
/*
* ============= PUBLIC jiffy API =============
*/
/*
* Link functions
*/
void jf_link_setfreq (jf_setfreq_pt pfun);
void jf_link_value (jiffy_t* v);
/*
* User Functions
*/
void jf_deinit (void);
int jf_init (uint32_t jf_freq, uint32_t jiffies);
jiffy_t jf_per_usec (void);
void jf_delay_us (int32_t usec);
int jf_check_usec (int32_t usec);
jiffy.c:
#include "jiffy.h"
static jf_t _jf;
#define JF_MAX_TIM_VALUE (0xFFFF) // 16bit counters
//Connect the Driver's Set frequency function
void jf_link_setfreq (jf_setfreq_pt pfun) {
_jf.setfreq = pfun;
}
// Connect the timer's value to jiffy struct
void jf_link_value (jiffy_t* v) {
_jf.value = v;
}
// De-Initialize the jf data and un-connect the functions
// from the driver
void jf_deinit (void) {
memset ((void*)&_jf, 0, sizeof (jf_t));
}
// Initialise the jf to a desired jiffy frequency f
int jf_init (uint32_t jf_freq, uint32_t jiffies) {
if (_jf.setfreq) {
if ( _jf.setfreq (jf_freq, jiffies) )
return 1;
_jf.jiffies = jiffies;
_jf.freq = jf_freq;
_jf.jpus = jf_per_usec ();
return 0;
}
return 1;
}
// Return the systems best approximation for jiffies per usec
jiffy_t jf_per_usec (void) {
jiffy_t jf = _jf.freq / 1000000;
if (jf <= _jf.jiffies)
return jf;
else
// We can not count beyond timer's reload
return 0;
}
/*!
* \brief
* A code based delay implementation, using jiffies for timing.
* This is NOT accurate but it ensures that the time passed is always
* more than the requested value.
* The delay values are multiplications of 1 usec.
* \param
* usec Time in usec for delay
*/
void jf_delay_us (int32_t usec) {
jiffy_t m, m2, m1 = *_jf.value;
usec *= _jf.jpus;
if (*_jf.value - m1 > usec) // Very small delays will return here.
return;
// Delay loop: Eat the time difference from usec value.
while (usec>0) {
m2 = *_jf.value;
m = m2 - m1;
usec -= (m>0) ? m : _jf.jiffies + m;
m1 = m2;
}
}
/*!
* \brief
* A code based polling version delay implementation, using jiffies for timing.
* This is NOT accurate but it ensures that the time passed is always
* more than the requested value.
* The delay values are multiplications of 1 usec.
* \param
* usec Time in usec for delay
*/
int jf_check_usec (int32_t usec) {
static jiffy_t m1=-1, cnt;
jiffy_t m, m2;
if (m1 == -1) {
m1 = *_jf.value;
cnt = _jf.jpus * usec;
}
if (cnt>0) {
m2 = *_jf.value;
m = m2-m1;
cnt-= (m>0) ? m : _jf.jiffies + m;
m1 = m2;
return 1; // wait
}
else {
m1 = -1;
return 0; // do not wait any more
}
}
Hmmm you made it till here. Nice
So now you can use it in your application like this:
main.c:
#include "driver.h"
#include "jiffy.h"
void do_some_job1 (void) {
// job 1
}
void do_some_job2 (void) {
// job 2
}
int main (void) {
jf_link_setfreq ((jf_setfreq_pt)JF_setfreq); // link with driver
jf_link_value ((jiffy_t*)&JF_TIM_VALUE);
jf_init (1000000, 1000); // 1MHz timer, 1000 counts, 1 usec per count
// use delay version
do_some_job1 ();
jf_delay_us (300); // wait for at least 300 usec
do_some_job1 ();
// use polling version
do_some_job1 ();
while (jf_check_usec (300)) {
do_some_job2 (); // keep calling for at least 300 usec
}
}
I have faced a problem connected with GPIO interrupt.
The task is to make a simple UI interface, so I need to use 3 buttons.
The problem is that I don't understand how to use GPIO interrupt for different pins and all my buttons work the same way.
here is the code:
#include <m8c.h> // part specific constants and macros
#include "PSoCAPI.h" // PSoC API definitions for all User Modules
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int value; // the actual value which is used in the module
char string[16]; // string that is printed in LCD for user
} UI_ELEMENT;
#define FIRST_LEVEL 3
#define SECOND_LEVEL 3
#define PWM 0
#define PGA 1
#define ADC 2
#define PWM_STATE 0
#define PWM_PERIOD 1
#define PWM_WIDTH 2
#define PWM_STATE_OFF 0
#define PWM_STATE_ON 1
volatile int buttonRightPressed = 0;
#pragma interrupt_handler buttonRightInt
void buttonRightInt(void){
// disable button interrupt
M8C_DisableIntMask(INT_MSK0, INT_MSK0_GPIO);
buttonRightPressed = 1;
}
void initialize_LCD(void){
LCD_Position(0,0);
LCD_PrCString("PWM");
LCD_Position(1,0);
LCD_PrCString("< select >");
}
void update_LCD(int* lvl1){
if (*lvl1 == PWM || *lvl1 == 3){
LCD_Position(0,0);
LCD_PrCString("PWM");
*lvl1 = 0;
}
else if (*lvl1 == PGA){
LCD_Position(0,0);
LCD_PrCString("PGA");
}
else if (*lvl1 == ADC){
LCD_Position(0,0);
LCD_PrCString("ADC");
}
}
void main(void)
{
UI_ELEMENT userInterface[FIRST_LEVEL][SECOND_LEVEL];
int level_1_steper = PWM;
int i;
M8C_EnableGInt ; // Uncomment this line to enable Global Interrupts
PWM8_EnableInt();
LCD_Start();
M8C_EnableIntMask(INT_MSK0, INT_MSK0_GPIO);
initialize_LCD(); // set 'PWM' for upper row, '< select >' for lower row
while (1){
if (buttonRightPressed == 1){
for ( i = 0; i < 350; i++);
level_1_steper++;
update_LCD(&level_1_steper);
buttonRightPressed = 0;
// enable button interrupt again
M8C_EnableIntMask(INT_MSK0, INT_MSK0_GPIO);
}
}
}
Problem resolved! As usually solution is quite simple: use GPIO interrupt but test which button has been pressed. GPIO iterrupt:
void buttonInt(void){ // disable button interrupt
M8C_DisableIntMask(INT_MSK0, INT_MSK0_GPIO);
if (Right_Data_ADDR & Right_MASK) buttonRightPressed = 1;
if (Left_Data_ADDR & Left_MASK) buttonLeftPressed = 1;
if (Select_Data_ADDR & Select_MASK) buttonSelectPressed = 1;
}