Arduino conversions in C - c

void digitalClockDisplay(){
// digital clock display of the time
Serial.print(hour());
printDigits(minute());
Serial.println();
}
void printDigits(int digits){
// utility function for digital clock display: prints preceding colon and leading 0
Serial.print(":");
if(digits < 10)
Serial.print('0');
Serial.print(digits);
}
//I tried something like this
//void time(){
//char* hr = (char*)hour();
//Serial.println(hr);
//}
//But when I print it it gives a whole bunch of jibberish
Here are the two functions I'm using what I'm trying to do is make a function like the digitalClockDisplay function but one that returns the hour:minute as a char* once I have that I want to be able to compare that to another char*

hour() seems to be returning a int, so
char* hr = (char*)hour();
Serial.println(hr);
casts a int to a pointer and then sends the bytes at that (meaningless) address to Serial.
You probably want something like:
char hr[8];
snprintf(hr,8,"%i:%02i",hour(),minute());
Serial.println(hr);

Related

Confused about Passing user data to PortAudio Callbacks

This is my first post here and I'm fairly new to programming and especially with C. A couple weeks ago I started working through the Audio Programming Book(MIT press) and have been expand on some examples to try to understand things further.
I think my question lies with how I'm trying to pass data (retrieved from the user in an initialization function) to a PortAudio callback. I feel like what I've done isn't that different from the examples (both from the book and PortAudio's examples like paex_sine.c), but for some reason I can't my code to work and I've been banging my head against a wall trying to understand why. I've tried searching pretty extensively for solutions or example code to study, but I kind of don't know what I don't know, so that hasn't returned much.
How do I get user data into the callback?
Am I just not understanding how pointers and structs work and trying to force them to do things they don't want to?
Or, am I just overlooking something really obvious?
The following code either gives a really high pitched output, short high pitched blips, or no (audible) output:
#include <stdio.h>
#include <math.h>
#include "portaudio.h"
#define FRAME_BLOCK_LEN 64
#define SAMPLING_RATE 44100
#define TWO_PI (3.14159265f * 2.0f)
PaStream *audioStream;
double si = 0;
typedef struct
{
float frequency;
float phase;
}
paTestData;
int audio_callback (const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeinfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
paTestData *data = (paTestData*)userData;
float *out = (float*)outputBuffer;
unsigned long i;
// data->frequency = 400;
for(i = 0; i < framesPerBuffer; i++){
si = TWO_PI * data->frequency / SAMPLING_RATE; // calculate sampling-incr
*out++ = sin(data->phase);
*out++ = sin(data->phase);
data->phase += si; // add sampling-incr to phase
}
return paContinue;
}
void init_stuff()
{
float frequency;
int i;
PaStreamParameters outputParameters;
paTestData data;
printf("type the modulator frequency in Hz: ");
scanf("%f", &data.frequency); // get modulator frequency
printf("you chose data.frequency %.2f\n",data.frequency);
data.phase = 0.0;
printf("initializing Portaudio. Please wait...\n");
Pa_Initialize(); // initialize Portaudio
outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
outputParameters.channelCount = 2; /* stereo output */
outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
outputParameters.hostApiSpecificStreamInfo = NULL;
Pa_OpenStream( // open paStream object
&audioStream, // portaudio stream object
NULL, // input params
&outputParameters, // output params
SAMPLING_RATE, // SampleRate
FRAME_BLOCK_LEN, // frames per buffer
paNoFlag, // set no Flag
audio_callback, // callbak function address
&data ); // user data
Pa_StartStream(audioStream); // start the callback mechanism
printf("running... press space bar and enter to exit\n");
}
void terminate_stuff()
{
Pa_StopStream(audioStream); // stop callback mechanism
Pa_CloseStream(audioStream); // destroy audio stream object
Pa_Terminate(); // terminate portaudio
}
int main(void)
{
init_stuff();
while(getchar() != ' ') Pa_Sleep(100);
terminate_stuff();
return 0;
}
Uncommenting data->frequency = 400; at least plays a 400hz sine wave, but that ignores any user input done in init_stuff()
If I put a printf("%f\n",data->frequency); inside the callback, it prints 0.000000 or something like -146730090609497866240.000000.
It's pretty unpredictable, and this really makes me think it's pointer related.
My goal for this code is to eventually incorporate envelope generators to change the pitch and possibly incorporate wavetable oscillators so I'm not calculating sin(x) for every iteration.
I can get envelopes and wavetables to work while using a blocking API like portsf that's used in the book, but trying to adapt any of that code from earlier chapters to use PortAudio callbacks is turning my brain to mush.
Thanks so much!
The problem you're having with your callback data is that it goes out of scope and memory is deallocated as soon as init_stuff finishes execution.
You should allocate memory for your callback data using malloc or new and passing the pointer to it for the callback.
For example:
void init_stuff()
{
float frequency;
int i;
PaStreamParameters outputParameters;
paTestData *data = (paTestData *) malloc(sizeof(paTestData));
printf("type the modulator frequency in Hz: ");
scanf("%f", &(data->frequency)); // get modulator frequency
printf("you chose data.frequency %.2f\n",data->frequency);
data->phase = 0.0;
...
Pa_OpenStream( // open paStream object
&audioStream, // portaudio stream object
NULL, // input params
&outputParameters, // output params
SAMPLING_RATE, // SampleRate
FRAME_BLOCK_LEN, // frames per buffer
paNoFlag, // set no Flag
audio_callback, // callbak function address
data );
...
I wasn't able to get the original code working using malloc but based on both suggestions, I realized another workable solution. Because running init_stuff() caused my data to get deallocated, I'm for now just making all my assignments and calls to Pa_OpenStream() from main.
Works beautifully and I can now send whatever data I want to the callback. Thanks for the help!

pgm_read_ and PROGMEM - unexpected behaviour

I made a program that plays a song (using buzzer) saved in array:
(...)
//function which plays a single note
void playNote(int8 wavelength, int duration) {
if (wavelength != 1) {
OCR0A = wavelength; /* set pitch */
SPEAKER_DDR |= (1 << SPEAKER); /* enable output on speaker */
}
while (duration) { /* Variable delay */
_delay_ms(1);
duration--;
}
SPEAKER_DDR &= ~(1 << SPEAKER); /* turn speaker off */
//function which plays song from array
void playSong( int8 *song,int tempo){
int length_16_note = tempo;
for( int8 i = 0;song[i]) ; i += 2){
playNote(song[i],song[i+1]*length_16_note);
_delay_ms(15);
}
}
int main(void){
//array of macros and lenghts of notes
int8 song1[] = {
C,4, E1,4, F1,3, E1,3, F1,2,
F1,2, F1, 2, B1,2, A1,2, G1,1, F1,2, G1,5,
G1,4, B1,4, C1,3, F1,3, E1,2,
B1,2, B1,2, G1,2, B1,2,
B1,3, C1,13, 0};
//initialize a timer
initTimer();
//play song
playSong(song1, 150)
}
I omitted some parts of it, but this code works just fine. And now I want to save my song into program memory so I change:
#include <avr/pgmspace.h>
(...)
int8 song1[] PROGMEM = {...}
void playSong( int8 *song, int tempo){
int length_16_note = tempo;
for( int8 i = 0; pgm_read_byte(&(song[i])) ; i += 2){
playNote(pgm_read_byte(&(song[i])), pgm_read_byte(&(song[i+1]))*length_16_note);
_delay_ms(15);
}
}
And when I run that code on Arduino, I get random beeps with random duration (much longer that expected). It looks like pgm_read_byte(&(song[i])) returns random values.
I tried to extract code from function playSong to main in order not to pass an array as an argument to the function and nothing changed. So what is wrong with this code?
I'm not sure this is the reason but my first guess is that you get longer durations than expected because your for loop looks like this:
for( int8 i = 0; pgm_read_byte(&(song[i])) ; i += 2)
This means every time the for loop is executed, the program checks the data in program space, as it is the loop condition.
There is a warning stated in the avr-libc user manual concerning the use of program memory reads in loops and functions, see below.
The macros and functions used to retrieve data from the Program Space have to generate some extra code in order to actually load the data from the Program Space. This incurs some extra overhead in terms of code space (extra opcodes) and execution time. (...) But you should be aware of this so you can minimize the number of calls within a single function that gets the same piece of data from Program Space.
Moreover, you make two additional calls to program flash inside the for loop. All this means, that to change the note, the program needs to wait for 3 byte reads from program memory and an additional 15 ms delay. As a result, the notes are much longer than expected.
I suggest the program should first read the whole song into some kind of a buffer in RAM, and play it afterwards directly from RAM.
Problem solved. The issue here was the fact that array song1 is declared in main() function. I had to declare array as global data before function definitions:
#include (...)
#define (...)
const int8 song1[] PROGMEM = {
C,4, E1,4, F1,3, E1,3, F1,2,
F1,2, F1, 2, B1,2, A1,2, G1,1, F1,2, G1,5,
G1,4, B1,4, C1,3, F1,3, E1,2,
B1,2, B1,2, G1,2, B1,2,
B1,3, C1,13, 0};
void playNote(int8 wavelength, int16 duration){...}
void playSong( int8 *song, int16 tempo){...}
int main(void){...}
It was hard to see the problem in my question above, because I wrote code in misleading way (in second quote I wrote array before function definition - but in original code it was in the same place as before). I'm sorry for that.

Can't extract an integer from a thermometer byte reading

Afternoon all,
Apologies if this question is in the wrong format or in the wrong place, if this is the case, please flag and I'll change it or take it elsewhere.
I am using a development board to send a temperature reading to an LCD panel and I am really struggling to comprehend as to why the temperature at the moment that the program is run isn't being printed onto my LCD. A lot of the code is from framework given to me and is correct as far as I can tell.
My question stems from these functions:
uch get_temp()
{
int i;
DQ_HIGH();
reset(); //reset,wait for 18b20 responsion
write_byte(0XCC); //ignore ROM matching
write_byte(0X44); //send temperature convert command
for(i=20;i>0;i--)
{
//display(); //call some display function,insure the time of convert temperature
}
reset(); //reset again,wait for 18b20 responsion
write_byte(0XCC); //ignore ROM matching
write_byte(0XBE); //send read temperature command
TLV=read_byte(); //read temperature low byte
THV=read_byte(); //read temperature high byte
DQ_HIGH(); //release general line
TZ=(TLV>>4)|(THV<<4)&0X3f; //temperature integer
TX=TLV<<4; //temperature decimal
if(TZ>100)
{
TZ/100;
} //not display hundred bit
ge=TZ%10; //integer Entries bit
shi=TZ/10; //integer ten bit
wd=0;
if (TX & 0x80)
wd=wd+5000;
if (TX & 0x40)
wd=wd+2500;
if (TX & 0x20)
wd=wd+1250;
if (TX & 0x10)
wd=wd+625; //hereinbefore four instructions are turn decimal into BCD code
shifen=wd/1000; //ten cent bit
baifen=(wd%1000)/100; //hundred cent bit
qianfen=(wd%100)/10; //thousand cent bit
wanfen=wd%10; //myriad cent bit
NOP();
return TZ;
}
I have modified this function so that it should return the temperature integer (unsigned char TZ)
This function is then called here:
void Init_lcd(void)
{
ADCON1 = 0x07; //required setting of analog to digital
uch Temp;
TRISD = 0x00;
TRISA1 = 0;
TRISA2 = 0;
TRISA3 = 0;
writeCommand(0x0f);
writeCommand(0x38); //set to two line mode
clearDisplay();
writeString("MAIN MENU");
Temp = get_temp();
writeString(Temp);
writeCommand(0xC0); //change cursor line
}
It isn't printing anything after "MAIN MENU", which obviously means I'm doing something wrong. I can provide further clarification/code on request.
I should probably mention that I am NOT only simply looking for an answer of "paste this in and it'll work". Any feedback in which I understand my mistake and how to fix it is greatly appreciated.
Thanks in advance!
EDIT:
A few people are asking about my writing functions so for further clarification I'll paste them here:
void writeChar(unsigned char ch)
{
lcd = ch;
RS = 1;
RW =0;
E = 1;
lcdDelay();
E=0;
}
void writeString(char *stringToLcd)
{
while(*stringToLcd > 0)
{
writeChar(*stringToLcd++);
}
}
Temp is an unsigned char
uch Temp;
//...
Temp = get_temp();
writeString(Temp);
So, using writeString() will produce undefined results.
You should use write() instead (depending on the library you're using).
But you probably want to convert the return value of get_temp() to an ASCII string first, and display that using writeString().
Update:
void writeString(char *stringToLcd)
This function needs a char*, so you can't provide a single uch.
You need to convert Temp to a string first, using itoa() for example.
I could suggest you to implement a new function
void writeUCH(uch value)
{
unsigned char test = (value >= 100) ? 100 : (value >= 10) ? 10 : 1;
while(test > 0)
{
writeChar((value/test)+'0');
value = value%test;
test /= 10;
}
}
this line:
TZ/100;
will result in no change to TZ
what you really want is this:
TZ = TZ%100;
the value returned from get_temp() is an integer, not a ascii string. I would expect the LCD needs ascii characters, not the binary value of the bytes of an int variable.

Arduino: string to multiple variables

I'm trying to send the data from two sensors through 433MHz radio communication. I have succeeded in sending and receiving the string(array of char) "number1,number2".
Now I'm trying to store both numbers in separate int variables (the values are over 256).
I've tried with almost everything (sscanf and atoi mainly), but it does not seem to work.
To A0 and A1 I have connected two potentiometers, whose values I want to store in valorX and valorY in the receiver arduino.
What do you suggest?
I cannot assure I used correctly sscanf and atoi.
Transmitter code:
#include <VirtualWire.h>
int xvalue;
int yvalue;
void setup() {
Serial.begin(9600);
vw_set_ptt_inverted(true); //
vw_set_tx_pin(12);
vw_setup(4000);// speed of data transfer Kbps
}
void loop() {
xvalue=analogRead(A0);
yvalue=analogRead(A1);
int envioX = map(xvalue, 0, 1023, 001, 1000); //I prefer to not send 0
int envioY = map(yvalue, 0, 1023, 001, 1000);
//Mando los datos del joystic
char envioXY[]="";
sprintf(envioXY,"%d,%d",envioX,envioY);
EnviarDatos(envioXY);
delay(1000);
}
void EnviarDatos(char datos[]){
vw_send((uint8_t *)datos, strlen(datos)); //vw_send(message, length)
vw_wait_tx(); // Wait until the whole message is gone
}
Receiver code:
#include <VirtualWire.h>
char recibo[8]="";
int valorX;
int valorY;
void setup(){
vw_set_ptt_inverted(true); // Required for DR3100
vw_set_rx_pin(12);
vw_setup(4000); // Bits per sec
vw_rx_start(); // Start the receiver PLL running
Serial.begin(9600);
Serial.println("setup");
}
void loop(){
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
if (vw_get_message(buf, &buflen)){ //check to see if anything has been received
for(int i=0;i<buflen;i++){
recibo[i]=char(buf[i]);
Serial.print(recibo[i]);
}
recibo[buflen]=NULL;
//String str(recibo);
//What here to get both int??
}
}
What do you suggest?
I cannot assure I used correctly sscanf and atoi.
So the main question is how to convert "number1,number2" to int1=number1 and int2=number2.
Thanks and cheers
Gabriel
Transmitter code:
You must declare storage for the sprintf to use. You have only declared a 1-byte array which contains a NUL (0 byte) as the first and only element [0]:
char envioXY[]="";
Change it to this, which declares a character array with 24 elements:
char envioXY[ 24 ];
Although uninitialized, sprintf will set the array elements as it formats your 2 integers.
Receiver code:
After recibo[buflen] = NULL;, you can parse it with this:
sscanf( recibo, "%d,%d", &valorX, &valorY );
The format string matches the sprintf format, and the address of the two integers is passed in, not just the two integers.

Sending decimals using radio.write(); with Arduino

I'm adapting a sketch I found to send sensor data over a wifi chip (Nrf2401), and although I get the message through, the value I send contains decimals (e.g. 24.59), but the received message will only be 24.
I'm sure there's something wrong on the transmitter part of the code, but I can't see what.
Here's my code:
#include <RF24.h>
#include <RF24_config.h>
#include <SPI.h>
#include <OneWire.h>
#include <DallasTemperature.h>
OneWire oneWire(4);
DallasTemperature sensors(&oneWire);
// ce,csn pins
RF24 radio(8,7);
unsigned char data[3] = {
0};
unsigned long count=0;
void setup(void)
{
sensors.begin();
Serial.begin(57600);
Serial.println("**************V1 Send Sensor Data***********");
radio.begin();
radio.setPALevel(RF24_PA_LOW);
radio.setChannel(0x4c);
// open pipe for writing
radio.openWritingPipe(0xF0F0F0F0E1LL);
radio.enableDynamicPayloads();
radio.setAutoAck(true);
radio.powerUp();
Serial.println("...Sending");
}
void loop(void)
{
sensors.requestTemperatures();
float currentTemp;
currentTemp = sensors.getTempCByIndex(0);
//assign 'T' to represent a Temperature reading
data[0] = 'T';
data[1] = currentTemp;
count++;
// print and increment the counter
radio.write(data, sizeof(float)+1);
Serial.print("Temperature sent: ");
Serial.println(currentTemp);
// pause a second
delay(500);
}
In this example, when I print currentTemp, it will display the decimals, but if I print data[1], it won't.
What am I missing?
You are assigning data [1] = currentTemp. Current temp is a float, not a character so this won't work. Decimals are lost because the float will be cast to a char in the assignment. Make data into a larger buffer and use sprintf to print currentTemp if you want to use it as a string. Really you should be writing just currentTemp to the radio and formatting on the other end, which will make the operation faster and require less bandwith to transmit (not to mention that transmitting and formatting are different concerns and should be separated, not coupled, when possible).

Resources