How to correctly monitor a variable value on the lcd? - avr

i'm displaying the temperature on 16x2 LCD using atmega16 microcontroller ,
in the super loop i'm calling the function to display the temperature on the screen , in case the temperature is 136C ( for example ) and temperature becomes 50C , the screen displayed 50CC , i want it to be 50C , how to modify the function to handle this ?
#include "lcd.h"
#include "adc.h"
#include "stdio.h"
#include "stdlib.h"
uint8 g_flag = 0 ;
uint16 g_adc_value = 0 ;
float32 g_voltage = 0 ;
float32 g_temprature = 0 ;
float32 g_resolution = 0.0048828 ;
void display_temprature(sint16 a_temprature) ;
int main(void)
{
LCD_init() ;
ADC_init() ;
LCD_displayStringRowCol(0 , 1 , "Temprature is") ;
while(1)
{
g_adc_value = ADC_readChannel(1) ;
g_voltage = g_adc_value*g_resolution ;
g_temprature = g_voltage / 0.01 ;
display_temprature((sint16)g_temprature) ;
}
}
void display_temprature(sint16 a_temprature)
{
LCD_goToRowCol(1 , 7) ;
LCD_integerToString(a_temprature) ;
LCD_displayCharacter(223) ;
LCD_displayCharacter('C') ;
}

There are two simple ways to solve this issue:
Issue a "clear screen" command to the LCD to wipe out previous
output.
Write a string of spaces long enough to clear the previous output.
The main problem you're seeing is that the end of the longer string, ending in 'C' is not being erased when you later output the shorter string, also ending in 'C'. So one of the two methods above should solve your problem.

Related

Does system time tick on Arduino?

After setting system time via a call to a real-time-clock (RTC), repeated calls to time() always return the same value. Does the system time actually progress on Arduinos or do I need to continue querying the RTC every time I need the time?
To illustrate:
void InitRTC(void) {
DateTime rtcDT; // type defined by the RTC library
time_t bin_time;
rtcDT = rtc.now();
bin_time = rtcDT.secondstime(); // returns unixlike time
set_system_time(bin_time); //AVR call to set the sys time
}
void Dump(time_t t) {
char debug_log_message[MAX_DEBUG_LENGTH];
sprintf(debug_log_message, " time_t:\t %lu", t);
DebugLog(debug_log_message); //....routine to print to the serial port
}
void setup() {
InitRTC();
time_t now;
while (1) {
now = time(0);
Dump(now);
}
}
(safety checks omitted, serial code omitted).
This simply prints the same time for ever - it never progresses!
The standard library has few platform dependencies, so is very portable. However one of those dependencies is the source for real-time, which is entirely platform dependent, and as such it is common for libraries to leave the function as a stub to be re-defined by the user to suit the specific platform or to implement hook functions or call-backs to run the standard library clock.
With the avr-libc used by AVR based Arduino platformsfFor time() to advance it is necessary to call the hook function system_tick() at 1 second intervals (typically from a timer or RTC interrupt) (refer to the avr-libc time.h documentation. It is also necessary to set the time at initialisation using the set_system_time() function.
Invoking system_tick() from a 1Hz timer will then maintain time(), but it is also possible to use an RTC alarm interrupt, by advancing the alarm match target on each interrupt. So you might for example have:
void rtc_interrupt()
{
// Set next interrupt for 1 seconds time.
RTC rtc ;
int next = rtc.getSeconds() + 1 ;
if( next == 60 )
{
next = 0 ;
}
rtc.setAlarmSeconds( next ) ;
// update std time
system_tick() ;
}
void init_system_time()
{
tm component_time ;
RTC rtc ;
// Get *consistent* time components - i.e ensure the
// components are not read either side of a minute boundary
do
{
component_time.tm_sec = rtc.getSeconds() ;
component_time.tm_min = rtc.getMInutes(),
component_time.tm_hour = rtc.getHours(),
component_time.tm_mday = rtc.getDay(),
component_time.tm_mon = rtc.getMonth() - 1, // January = 0 in struct tm
component_time.tm_year = rtc.getYear() + 100 // Years since 1900
} while( component_time.tm_min != rtc.getMinutes() ) ;
set_system_time( mktime( &component_time ) - UNIX_OFFSET ) ;
// Set alarm for now + one second
rtc.attachInterrupt( rtc_interrupt ) ;
rtc.setAlarmSeconds( rtc.getSeconds() + 1 ) ;
rtc.enableAlarm( rtc.MATCH_SS ) ;
}
An alternative is to override time() completely and read the RTC directly on each call - this has the advantage of not requiring any interrupt handlers for example:
#include <time.h>
extern "C" time_t time( time_t* time )
{
tm component_time ;
RTC rtc ;
// Get *consistent* time components - i.e ensure the
// components are not read either side of a minute boundary
do
{
component_time.tm_sec = rtc.getSeconds() ;
component_time.tm_min = rtc.getMInutes(),
component_time.tm_hour = rtc.getHours(),
component_time.tm_mday = rtc.getDay(),
component_time.tm_mon = rtc.getMonth() - 1, // January = 0 in struct tm
component_time.tm_year = rtc.getYear() + 100 // Years since 1900
} while( component_time.tm_min != rtc.getMinutes() ) ;
return mktime( &component_time ) ;
}
I have assumed that the Arduino library getYear() returns years since 2000, and that getMonth() returns 1-12, but neither is documented, so modify as necessary.
Linking the above function before linking libc will cause the library version to be overridden.

OS X AudioUnit: kAudio_ParamError when setting misc properties on a Generator

I'm building a simple AudioUnit app which should use an AUGraph to connect a generator (which generates, say, a sine wave) to a format converter (because that seems like what I need) to an output device.
Code snippets:
{
AudioComponentDescription desc ;
desc.componentType = kAudioUnitType_Generator ;
desc.componentSubType = kAudioUnitSubType_ScheduledSoundPlayer ;
desc.componentFlags = 0 ;
desc.componentFlagsMask = 0 ;
desc.componentManufacturer = kAudioUnitManufacturer_Apple ;
status = AUGraphAddNode ( mGraph , &desc , &mGeneratorNode ) ;
checkOSStatus ( "creating generator node" , status ) ;
}
I do similarly for mConverterNode with kAudioUnitType_FormatConverter/kAudioUnitSubType_AUConverter and for mOutputNode with kAudioUnitType_Output/kAudioUnitSubType_DefaultOutput.
I then open the graph:
AUGraphOpen ( mGraph ) ; // error checking code omitted from example
I then get references to them:
AUGraphNodeInfo ( mGraph , mGeneratorNode , 0,&mGeneratorRef ) ; // error checking code omitted from example
I then set the format:
{
AudioStreamBasicDescription format ;
format.mSampleRate = mSamplingRate ;
format.mFormatID = kAudioFormatLinearPCM ;
format.mFormatFlags = kAudioFormatFlagIsSignedInteger ;
format.mFramesPerPacket = 1 ;
format.mChannelsPerFrame = 1 ; // mono
format.mBitsPerChannel = 16 ;
format.mBytesPerFrame = format.mBitsPerChannel*format.mChannelsPerFrame/8 ;
format.mBytesPerPacket = format.mBytesPerFrame*format.mFramesPerPacket ;
status = AudioUnitSetProperty ( mGeneratorRef , kAudioUnitProperty_StreamFormat , kAudioUnitScope_Output , kOutputBus , &format,sizeof(format) ) ;
checkOSStatus ( "setting output format" , status ) ;
}
(Note: kOutputBus is an enum to 0; it's an anachronism from a previous example I found. Also, mSamplingRate is a size_t whose value is 48000)
And set the render callback:
{
AURenderCallbackStruct cb ;
cb.inputProc = &_callbackProxy ;
cb.inputProcRefCon = static_cast<void*> ( this ) ;
status = AudioUnitSetProperty ( mGeneratorRef , kAudioUnitProperty_SetRenderCallback , kAudioUnitScope_Output , 0 , &cb,sizeof(cb) ) ;
checkOSStatus ( "setting the generator callback" , status ) ;
}
However, for both the stream format and the render callback I get kAudio_ParamError back as the resultant status.
No matter what I do (mono/stereo, when I place that command, etc), I cannot make it work.
Note: I later do this:
AUGraphConnectNodeInput ( mGraph , mGeneratorNode,0 , mConverterNode,0 ) ;
AUGraphConnectNodeInput ( mGraph , mConverterNode,0 , mOutputNode,0 ) ;
AUGraphInitialize ( mGraph ) ;
AUGraphStart ( mGraph ) ;
// again, error-checking code omitted from example
And it works........ But I can't set those properties and therefore can't generate audio.
What am I missing?
(To people with 1500+ reputation: please make an "osx-sierra" tag; I'm a bit shy of that mark)
From an obscure comment at the end of this:
https://discussions.apple.com/thread/1989797?tstart=0
I ran AUGraphOpen at the very beginning before creating things (why?) and it worked.
But then I was getting invalid format errors, so I set the format on the input of the converter instead of the output of the generator.
But then it wasn't calling the render callback, so I removed the generator altogether and put the render callback on the input of the converter.
At this point, it worked and is generating my sound.
I hope this helps somebody else in the future with this so-horribly-documented API.

How to compare enum in arduino?

I am facing an issue with arduino, since I want to change the state of my device using an enum, but it doesn't seeem to work, my code looks like below. I am not entirely sure where it goes wrong, I think as well that the comparison between settingTo and toP2P could be wrong?
Thanks in advance!
String toP2P = "503250"
String toABP = "414250";
String settingTo = LoRa_Tx.dataRX.substring(indx);
if( settingTo == toP2P ) {
//switching to P2P
Serial.println("current mode 1 "+(String) LoRa_Tx.current_modeRxTx);
if(LoRa_Tx.current_modeRxTx != LoRa_Tx.LoRaMod){
LoRa_Tx.current_modeRxTx = LoRa_Tx.LoRaMod;
}
} else if(settingTo == toABP){
//switching to ABP
if(LoRa_Tx.current_modeRxTx != LoRa_Tx.LoRaWan){
LoRa_Tx.current_modeRxTx = LoRa_Tx.LoRaWan;}
}
}
My class has the enum defined as
typedef enum modeRxTx{LoRaMod, LoRaWan, Idle} ;
modeRxTx current_modeRxTx = Idle;
In general, you should avoid the String class, as it will eventually cause problems. However, given that the LoRa_Tx appears to have a String member, here is one way to watch for those two modes:
if ((indx > -1) && (LoRa_Tx.dataRx.length() >= indx+5)) {
const char *settingTo = &LoRa_Tx.dataRx.c_str()[ indx ];
if ( strncmp_P( settingTo, PSTR("503250"), 6 ) == 0 ) {
//switching to P2P
Serial.print( F("current mode 1 ") ); // <-- saves RAM!
Serial.println( LoRa_Tx.current_modeRxTx );
if(LoRa_Tx.current_modeRxTx != LoRa_Tx.LoRaMod) {
LoRa_Tx.current_modeRxTx = LoRa_Tx.LoRaMod;
}
} else if ( strncmp_P( settingTo, PSTR("414250"), 6 ) == 0 ) {
//switching to ABP
if(LoRa_Tx.current_modeRxTx != LoRa_Tx.LoRaWan) {
LoRa_Tx.current_modeRxTx = LoRa_Tx.LoRaWan;
}
}
}
Instead of creating a substring, it just makes a pointer to the actual characters of data_Rx. The c_str() function returns a pointer to the first character (zero-based index) or the String, and the [ indx ] is the first of the mode number characters. Finally, the & is a pointer to the first mode number character.
Next, it uses a standard library function, strncmp_P (documented here), to compare those mode number characters with the modes you are looking for, and it only compares up to 6 characters. You don't say if there's a delimiter after "503250", so I don't know if "50325076" is possible and should be rejected.
The strncmp_P expects to get a PROGMEM string as the second argument, not just a const char *, so that's what the PSTR macro does. This saves RAM because the PSTR will be stored and compared from FLASH memory (aka PROGMEM). The Serial.print statements should use the F() macro for the same reason.

How to find the dpi of a monitor on which a specific window is placed in linux?

I want to change the font size when my application window moves from one monitor to another depending on the underlying dpi of destination monitor.
I played with xrandr, xdpyinfo and xlib. I looked at the source code but I couldn't find a way to associate the monitor on which the window (window id) is placed.
Qt has QDesktopWidget, which provides physicalDpiX/Y but only (so it seems) for the primary monitor.
xrandr.h contains XRROutputInfo which delivers mm_width and mm_height, but how can I make the connection to a window id?
Since this question got some attention, I want so share my research. I haven not found a perfect solution. It looks like it's not possible.
But playing with the following code snip will probably help you. The idea is to calculate the underlying display by comparing the window position. If the position is larger then the first screen's resolution, and must be the 2nd monitor. Pretty straight forward.
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
#include <stdio.h>
#include <stdlib.h>
// compile: g++ screen_dimension.cpp -lX11 -lXrandr
int main()
{
int wid = atoi( getenv( "WINDOWID" ) );
printf("window id: %i\n", wid);
Display * dpy = XOpenDisplay(NULL);
int screen = DefaultScreen(dpy);
Window root = DefaultRootWindow(dpy);
XRRScreenResources * res = XRRGetScreenResourcesCurrent(dpy, root);
XRROutputInfo * output_info;
for (int i = 0; i < res->noutput; i++)
{
output_info = XRRGetOutputInfo (dpy, res, res->outputs[i]);
if( output_info->connection ) continue; // No connection no crtcs
printf(" (%lu %lu) mm Name: %s connection: %i ncrtc: %i \n", output_info->mm_width
, output_info->mm_height
, output_info->name
, output_info->connection
, output_info->ncrtc
);
}
printf("crtcs:\n");
for( int j = 0; j < output_info->ncrtc; j++ ) {
XRRCrtcInfo * crtc_info = XRRGetCrtcInfo( dpy, res, res->crtcs[ j ] );
if( not crtc_info->noutput ) continue;
printf("%i w: %5i h: %5i x: %5i y: %i\n", j
, crtc_info->width
, crtc_info->height
, crtc_info->x
, crtc_info->y
);
}
}
There are actually 2 functions to query resources about the screens:
XRRGetScreenResourcesCurrent and XRRGetScreenResources. The first one returns some cached value, while the latter one asks the server which may introduce polling. The description (search for RRGetScreenResources):
https://www.x.org/releases/X11R7.6/doc/randrproto/randrproto.txt
Someone went through the trouble timing it:
https://github.com/glfw/glfw/issues/347
XRRGetScreenResourcesCurrent: Tipically from 20 to 100 us. h
XRRGetScreenResources: Typically from 13600 to 13700 us.
Ok, since there is no further discussion here and I am convinced my little program (see above) works, I declare it now as: Answered!
Compile instructions are
g++ screen_dimension.cpp -lX11 -lXrandr
(also added as comment above)
Why so complicated ?! Just get the info from screen where your window is attached.
double dDisplayDPI_H,dDisplayDPI_V;
dDisplayDPI_H = ((double)DisplayWidth( dpy, scr ))/(((double)DisplayWidthMM( dpy, scr ))/25.4);
dDisplayDPI_V = ((double)DisplayHeight( dpy, scr ))/(((double)DisplayHeightMM( dpy, scr ))/25.4);

libb64 C routines proper usage

I am having trouble with the C routines in libb64, here is my code:
base64_encodestate state;
int outBufLen = 2 * nInBuf;
*outBuf = new char[outBufLen];
base64_init_encodestate(&state);
int r1 = base64_encode_block(inBuf, nInBuf, *outBuf, &state);
int r2 = base64_encode_blockend(*outBuf, &state);
base64_init_encodestate(&state);
This puts the = at the beginning, not at the end.
So I tried this:
base64_encodestate state;
int outBufLen = 2 * nInBuf;
*outBuf = new char[outBufLen];
base64_init_encodestate(&state);
int r1 = base64_encode_block(inBuf, nInBuf, *outBuf, &state);
int r2 = base64_encode_blockend(*outBuf+ r1, &state);
base64_init_encodestate(&state);
This works, but not for "large" (~800KB text) files, then it skips the end = entirely. In that case base64_encode_blockend(code_out,state), enters case step_C where state->result = 0. I tried writing the b64 data to a file using the size reported by the libb64 functions, but it misses the end or is impartial. Im not sure.
I'm pretty much fed up with this. I based my code on the struct encode and decode.
Also do anyone know if there is a Windows API for base64 encode/decode? I am not using any C++ standard stuff, thats why I don't use the structs.

Resources