Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
8 years, 5 months ago.
Using pc.getc() and interrupts
Hello mbed community!
My code below generates waveforms and scales them, based on inputs from the keyboard. One key specifies one of four waveforms, and another key specifies the peak to peak output voltage. I must enter both keys in order for anything to happen. All of this is fine, but once those keys are entered, I cannot change the waveform or output voltage without resetting the mbed and entering two new keys.
Ideally, I would like to be able to switch between waveforms and voltages real-time. I have tried researching interrupts but cannot figure it out. Any help is greatly appreciated!
main.cpp
#include "mbed.h" #include "mcp4725.h" #include "math.h" Serial pc(USBTX, USBRX); SPI spi(p11, p12, p13); // SPI Bus (mosi, miso, sclk) DigitalOut cs(p14); // Chip Select Pin for DigiPot // Class instantiation (similar to Serial pc(USBTX, USBRX) in function) MCP4725 wave(p9, p10, MCP4725::Fast400kHz, 0); const double PI = 3.1415926535897932384626433832795; // For the Sine Waves int DesiredVoltage; // Function Parameter unsigned char VoltageCode; // Function Parameter /*------------------------------Function Prototypes---------------------------------------*/ unsigned char VoltageLevel (int DesiredVoltage); // Function to seperate possible levels void ScaleVoltage (unsigned char VoltageCode); // Function to write to digipot int main() { // Print to terminal pc.printf("Starting DAC Output.\n"); pc.printf("First enter the Desired Waveform.\n"); pc.printf("Then select the DigiPot Output Voltage.\n"); char Waveform = pc.getc(); int DesiredVoltage = pc.getc(); while(1) { /*-------------------------Stop DAC Output-----------------------------*/ if(Waveform == 'O') // Letter, not zero { pc.printf("Message Recieved. Stopping output."); wave.write(MCP4725::Normal, (0x000), false); } /*-------------------------1-Hz Square Wave----------------------------*/ if(Waveform == 'A') { wave.write(MCP4725::Normal, (0xFFF), false); wait(0.5); wave.write(MCP4725::Normal, (0x000), false); wait(0.5); VoltageLevel(DesiredVoltage); ScaleVoltage(VoltageCode); } /*------------------------10-Hz Square Wave----------------------------*/ if(Waveform == 'B') { wave.write(MCP4725::Normal, (0xFFF), false); wait(0.05); wave.write(MCP4725::Normal, (0x000), false); wait(0.05); VoltageLevel(DesiredVoltage); ScaleVoltage(VoltageCode); } /*--------------------------1-Hz Sine Wave-----------------------------*/ if(Waveform == 'C') { for(int i = 0; i <= 1000; i++) { wave.write(MCP4725::Normal, (0xFFF*(0.5*sin(2*PI*i/1000)+0.5)), false); wait_us(860); } VoltageLevel(DesiredVoltage); ScaleVoltage(VoltageCode); } /*--------------------------10-Hz Sine Wave----------------------------*/ if(Waveform == 'D') { for(int i = 0; i <= 1000; i++) { wave.write(MCP4725::Normal, (0xFFF*(0.5*sin(10*2*PI*i/1000)+0.5)), false); wait_us(860); } VoltageLevel(DesiredVoltage); ScaleVoltage(VoltageCode); } } // End while loop } //End main /*------------------Function to Separate Voltage Levels--------------------*/ unsigned char VoltageLevel (int DesiredVoltage) { if(DesiredVoltage == '0') { VoltageCode = 0x00; } if(DesiredVoltage == '1') // For 1Vpp output { VoltageCode = 0x26; } if(DesiredVoltage == '2') // For 2Vpp output { VoltageCode = 0x4D; } if(DesiredVoltage == '3') // For 3Vpp output { VoltageCode = 0x74; } if(DesiredVoltage == '4') // For 4Vpp output { VoltageCode = 0x9B; } if(DesiredVoltage == '5') // For 5Vpp output { VoltageCode = 0xC3; } return VoltageCode; } /*------------------------Function to Write to Digipot--------------------------------------*/ void ScaleVoltage (unsigned char VoltageCode) { // Chip must be deselected to begin cs = 1; // Setup the spi for 8 bit data, high steady state clock, // second edge capture, with a 1MHz clock rate spi.format(8,3); spi.frequency(1000000); // Select the device cs = 0; spi.write(0x11); // Command Byte spi.write(VoltageCode); // Set Wiper Position // Deselect the device cs = 1; }
2 Answers
8 years, 5 months ago.
No need to use interrupts for this, just check for key presses in your while loop and change settings based on what they press.
while(1) { if (pc.readable()) { // if they have pressed a key char tmp = pc.getc(); if ((tmp >= '0') && (tmp <= '9') // if it's a number set the voltage DesiredVoltage = tmp; else Waveform = tmp; // otherwise set the pattern } ...
Also for some reason you have a function that returns a value which you ignore and instead rely on it also setting a global variable. That's a good way to get very confused in the future. You should either use the returned value or no return anything and only use the global, the way you have it you can get some very confusing scoping problems.
The code below is (to me at least, personal preferences play a part in this sort of thing) somewhat cleaner. Or it would be if I hadn't kept the old code in there commented out to make it clearer what had changed. I removed the global variables, switched the long lists of if statements to using switch statements and added code to cope with invalid options.
#include "mbed.h" #include "mcp4725.h" #include "math.h" Serial pc(USBTX, USBRX); SPI spi(p11, p12, p13); // SPI Bus (mosi, miso, sclk) DigitalOut cs(p14); // Chip Select Pin for DigiPot // Class instantiation (similar to Serial pc(USBTX, USBRX) in function) MCP4725 wave(p9, p10, MCP4725::Fast400kHz, 0); const double PI = 3.1415926535897932384626433832795; // For the Sine Waves // No need to declare these as globals, You end up with multiple variables with the same name, which one you get depends on where you are in the code. //int DesiredVoltage; // Function Parameter //unsigned char VoltageCode; // Function Parameter /*------------------------------Function Prototypes---------------------------------------*/ unsigned char VoltageLevel (char DesiredVoltage); // Function to seperate possible levels void ScaleVoltage (unsigned char VoltageCode); // Function to write to digipot int main() { // Print to terminal pc.printf("Starting DAC Output.\n"); pc.printf("First enter the Desired Waveform.\n"); pc.printf("Then select the DigiPot Output Voltage.\n"); char Waveform = pc.getc(); char DesiredVoltage = pc.getc(); // changed from int to char // no need to set the divider every time, just set it once at the start. unsigned char VoltageCode = VoltageLevel(DesiredVoltage); ScaleVoltage(VoltageCode); while(Waveform != 'O') { if (pc.readable()) { // if they have pressed a key char tmp = pc.getc(); if ((tmp >= '0') && (tmp <= '9') { // if it's a number DesiredVoltage = tmp; // set the voltage code value VoltageCode = VoltageLevel(DesiredVoltage); // set the pot ScaleVoltage(VoltageCode); } else Waveform = tmp; // otherwise set the pattern } /*-------------------------Stop DAC Output-----------------------------*/ switch (Waveform) { case 'O': pc.printf("Message Recieved. Stopping output."); wave.write(MCP4725::Normal, (0x000), false); break; // example of how to do the same thing for multiple inputs... case 'A' : // this line only runs for 'A' case 'a': // this runs for both 'A' and 'a' wave.write(MCP4725::Normal, (0xFFF), false); wait(0.5); wave.write(MCP4725::Normal, (0x000), false); wait(0.5); // done once on a value change // VoltageLevel(DesiredVoltage); // ScaleVoltage(VoltageCode); break; // don't forget this or it will fall through to the next section below. /*------------------------10-Hz Square Wave----------------------------*/ case 'B': wave.write(MCP4725::Normal, (0xFFF), false); wait(0.05); wave.write(MCP4725::Normal, (0x000), false); wait(0.05); // done once on a value change // VoltageLevel(DesiredVoltage); // ScaleVoltage(VoltageCode); break; /*--------------------------1-Hz Sine Wave-----------------------------*/ case 'C': case 'c': for(int i = 0; i <= 1000; i++) { wave.write(MCP4725::Normal, (0xFFF*(0.5*sin(2*PI*i/1000)+0.5)), false); wait_us(860); } // done once on a value change // VoltageLevel(DesiredVoltage); // ScaleVoltage(VoltageCode); break; /*--------------------------10-Hz Sine Wave----------------------------*/ case 'D': for(int i = 0; i <= 1000; i++) { wave.write(MCP4725::Normal, (0xFFF*(0.5*sin(10*2*PI*i/1000)+0.5)), false); wait_us(860); } // done once on a value change // VoltageLevel(DesiredVoltage); // ScaleVoltage(VoltageCode); break; default: // what to do if they picked some other letter pc.printf("Invalid option. Please select a waveform type"); wave.write(MCP4725::Normal, (0x000), false); Waveform = pc.getc(); break; } // end switch } //End main /*------------------Function to Separate Voltage Levels--------------------*/ unsigned char VoltageLevel (char DesiredVoltage) { switch (DesiredVoltage) { case '0': // 0Vpp default: // wasn't a valid level, disable output return 0x00; break; // technically not needed due to the return above. case '1': // 1Vpp return 0x26; break; case '2': // 2Vpp return 0x4D; break; case '3': // 3Vpp return 0x74; break; case '4': // 4Vpp return 0x9B; break; case '5': // 5Vpp return 0xC3; break; } } /*------------------------Function to Write to Digipot--------------------------------------*/ void ScaleVoltage (unsigned char VoltageCode) { // Chip must be deselected to begin cs = 1; // Setup the spi for 8 bit data, high steady state clock, // second edge capture, with a 1MHz clock rate spi.format(8,3); spi.frequency(1000000); // Select the device cs = 0; spi.write(0x11); // Command Byte spi.write(VoltageCode); // Set Wiper Position // Deselect the device cs = 1; }
Yes!! That works great! Thank you Andy I really appreciate your help and the comments in the code!
posted by 08 Dec 2015Just to note this solution will block until the wave form has completed (upto 1 Second with 1Hz) where as interupts will allow to change on demand. Not to say Andy's work is wrong just different way to a solution it depends on your application. Kind Regards
posted by 08 Dec 2015Errrr. No. Blocking implies execution is paused for some reason e.g. calling getc() twice when there may only be one byte waiting. That can happen even in an interrupt (see your code above for an example of blocking code).
It is true that the wave will only switch pattern at the end of a cycle but that is also true of an interrupt based system unless you rewrote the entire program to generate the outputs based on a ticker. In that situation the main loop wouldn't then be generating the pattern and so could look for key presses meaning that you still don't need interrupts for the key detection.
Thinking about it a bit more the if (pc.readable()) should be while() rather than if() so that you can change pattern and amplitude at the same time if you hit the keys fast enough.
posted by 08 Dec 20158 years, 5 months ago.
An easy solution for your problem is to pc.getc() inside an interrupt when you microcontroler receives data. You do that by attaching one Handler, or Callback function to this interrupt. For example, I want to call HandlerRX whenever I receive data:
pc.attach(&HandlerRx, pc.RxIrq);
And that's it..
Hope I helped
You can do as follows
and you need a routine to be serviced....