Showing posts with label code. Show all posts
Showing posts with label code. Show all posts

Monday, December 26, 2011

Creating random numbers on a µC [code snippet]

This is a small C function, to feed srand() with a random seed. I wrote it some weeks ago just to test if it would be possible to get random seeds with an 8051 microcontroller without additional hardware. And yes, it is possible. I was using an AT89C51ED, but the code should work with every 8051 compatible microcontroller.
How does it work and why? I took a closer look in the data sheet of the µC and i saw that some bits and bytes in the special function registers (SFRs) are not initialized with "1" or "0". Some bits were marked with "x" and those are the interesting ones. The value of those bits can be "0" or "1" after power up - their initial value is random. All i had to do was to iterate over all those SFR-bytes and XOR them. I am sure generations of 8051 coders have had the same idea, but i did not study all available information regarding 8051 and random numbers.
Just call the function like that "srand(getRandom());", and you will have a new random seed, after each power up of the microcontroller. (A normal µC reset will not give you a new random seed!)

unsigned char getRandom( void )
{
     unsigned char *random;
     unsigned char k;
     unsigned char value;
    random = 0x80; //Starting address of the SFRs
    for (k=0; k <= 127; k++) //iterate over the 128 bytes of the SFRs:
        value ^= random[k]; //XOR the values
    return value; //return the random seed
}

Friday, July 22, 2011

Parsing source code files for function headers and function calls

Some weeks ago I wrote a small program, which is able to print a list of functions and function calls used in a program. It can parse a directory recursively for a given file type.

Here is the source code: functiondiagram.d
And here is the source as a "quote" (a function to present formated source code is missing on blogger.com...):
/*
    This console apllication written in D is able to parse C, C++, D and many more file types.
    It scans the files for functions and function calls and prints a list with all matches for every file.
    As first parameter you must specify a directory name, where the search will start. This folder will be scanned recursively for matches.
    The type of file must be specified by the second parameter.
  
    This code stands under the do-with-it-what-you-want license.
  
    Author: Energized
    E-mail: undervoltage@safe-mail.net
    Blog: http://electric-handicraft.blogspot.com
*/


import std.file;
import std.stdio;
import std.stream;
import std.regexp;

/*
TODO:
- Self defined data types are not recognized
- Comments will be parsed too. This can result in false "positives".
*/


/*
    Function is searching in a line of text/code for function calls and function headers:
*/
string[] returnFunctions( string data )
{
    string regex = r"([\w\d]+)\s*[(]";
    string[] rv;
  

    foreach( m; RegExp( regex, "ig" ).search( data ) )
    {
        if ( (m !is null) && (m.match(1) !is null) ) //is something was found:
        {
            //writefln("> '" ~ m.match(1) ~ "'");
            if ( RegExp( r"^(if|for|foreach|return|while|finally|try|catch)$" ).match( m.match(1) ) is null ) //is the match a reserved word?
            {
                rv ~= m.match(1); //if not, it will be part of our result

                //if no datatype is in front of the match, it is a function call:
                auto n = search( m.pre, r"^\s{0,}(string|bool|int|byte|char|long|short|float|double|void|signed|unsigned|HBITMAP)", "i" );
                if ( n is null )
                    rv ~= ";";
                else
                {
                    /*
                        If an assignment is done (function to variable), false positives will be produced.
                        Then the function call will be misinterpreted as a function header. Thats why we are searching for a
                        semicolon here. Is a semicolon in this line, it is a function call (or a forward declaration).
                    */
                    if ( std.string.find( m.post, ';' ) != -1 ) rv ~= ";";
                }
            }
        }
    }
    return rv;
}


/*
    Shows the result:
*/
void printTree( string[] data )
{
    if (data.length == 1)
        writefln( "\nFunction \"%s()\":", data[0] );
    else
    {
        foreach( t; data )
            if (t != ";") writefln("\t%s();", t);
    }
}


void main( char[][] parameters )
{
    string path = parameters[1];      //as first parameter the program needs a path name
    string extension = parameters[2]; //extension (like "*.cpp")
    string[] result = listdir( path, extension ); //crawl through all files with the given extension in the given directory and all sub directories and store the filenames in the "result" array.
  
    foreach( filename; result ) //scan one file after the other:
    {
        BufferedFile file = new BufferedFile( filename, FileMode.In ); //open the file for reading

        writefln( "\nFile: " ~ filename ); //print the filename
      
        foreach(ulong n, string line; file) //go through the lines and scan them for function names or function calls:
        {
            string[] functions = returnFunctions( line );
          
            if (functions !is null) printTree( functions ); //if the end of file is reached, print the result
        }
        file.close();
    }
}
 And here is an example, how the result looks like:

File: C:\functiondiagram.d

Function "returnFunctions()":
        RegExp();
        search();
        match();
        writefln();
        match();
        RegExp();
        match();
        match();
        match();
        search();
        done();
        call();
        find();

Function "printTree()":
        writefln();
        s();
        writefln();
        s();

Function "main()":

Function "extension()":
        listdir();
        BufferedFile();
        writefln();
        returnFunctions();
        printTree();
        close();

The program is not perfect yet. Some false positives are possible like in the example the function "s()" which is not a function but a regular expression.

Sunday, May 15, 2011

New firmware for the thermometer

Here is an up-to-date version of the clock-thermometer firmware: Thermometer4_-_LCD.c
Because of school I did not have much time to make improvements.

Sunday, September 26, 2010

Some C helper routines...

I wrote a small application for counting the number of lines (of code) in *.c files today.
As a side effect i have now some handy functions for different applications.
Luckily i had the passion to write them.


Lets take a look at the functions:
void findFiles( char *, void (char *, char *) );
Finds all files in a given folder + subfolders and calls a user defined callback function.

const char *getFileType( char * );
Returns the file extension of a given file.

const char *right( char *, int );
Returns 'i'  chars from the right side of an string (same function as the command 'right' in VBS).

Works with PellesC 6.00.4.
I used some non standard C functions in the code. So it will not work with every compiler without modifications.

Here is the library: utils.zip


(God damn...! The layout on blogger.com is so crapy)

Tuesday, February 23, 2010

Clock - some hints and thoughts

I have reprogrammed the clock-thermometer the first time after soldering it to the breadboard.

In the circuit diagram you can throw away jmp3 and jmp4 and replace them with a common jumper on the mass of D2 and R7.

Because my wall power supply not only outputs 9 V DC but also ~13 V AC, i decided to power the circuit with rechargeable batteries (4*1,2 V).

I thought it could help to change the following line:
degree = (degree * VREF) >> ADC_BITS;
to:
degree = ((degree * 1024) + (degree * 64) + (degree * 8) + (degree * 4)) >> ADC_BITS;

Where ADC_BITS is defined as 10 and VREF as 1100 (mV).
Indeed the code size shrinked from 3132 bytes to 3060 bytes, but the temperature was calculated wrong. The thermometer displayed a negative temperature, although my room was warm.

When i changed the code to:
degree = ((degree * 1024L) + (degree * 64L) + (degree * 8L) + (degree * 4L)) >> ADC_BITS;

The filesize was 3132 bytes again.

As you can see: the AVR GCC port isn't as stupid as you (or me) think. ;)

Happy soldering!

Monday, February 22, 2010

Clock-Thermometer with Attiny and LM35

Today i want to present you my last project i've made.
It's a more modern version of my first big µC project: a thermometer. (yeah!)
I finished it last sunday - at least the most parts of the project.

My first version i made months ago, was equiped with an Atmega8, four multiplexed 7 segment displays, "software" based USB and a batterie backup if no USB connection was in the near.
So far so good.

The negative points were:
It consumed a lot of power, it used tons of parts, it had some bugs i never killed and it only displayed the actual temperature.
I paused the project for a while.

By the time my µC skills increased and so on one day i decided to make a better version.
The requirements:
  • no batterie
  • no usb
  • no 7 segment display
  • should display something more than just temperature...
  • lesser parts
  • KISS!

That was the hour of birth for the thermometer version 4a:

The whole circuit is build around an Attiny84V and an LM35C.
The output is done on an LC Display from Displaytech.
1x16 Chars - or more precise: 2x8 Chars in one line.
Sadly without backlight.

After making some plans for the hard- and software parts i build up the circuit on an pinboard and then i made the software.
(Usually i never make plans for the software part.)
Last step was soldering the stuff onto a bredboard as you can see in the pictures below.
Because i made a lot of plans and "brain work" in the forefront, it was a very easy and straight forward implementation. No bigger problem appeared till now.

The circuit is using a wall power supply.
It is specified with 6 V DC, 300 mA and it is from an old wirless mouse charging station.
In idle time it delivers around 9 V and because the whole circuit consumes under 15 mA it will work in idle even when the circuit is connected. ^.^

As special feature i implemented a clock (wohoo!).
With three switches on the back you can set the hour, minute and the display mode.
Display mode means the appearance of the time and temperature on the LCD:
  • Mode 1: HH:MM:SS +/-TT,T°C
  • Mode 2: HH:MM +/-TT,T°C
  • Mode 3: HH:MM +/-TT°C
The thermometer should be able to display positive and negative temperatures in the range of -40 to +70°C.
But because it is getting warmer here outside i need some fridge to test the posibility of displaying negative values.
The build in clock is synced by an 16 MHz Quartz (CHKDIV8 is on - resulting in a clock speed of 2 MHz!).
The clock is not calibrated yet - but on the pinboard it was exact enough. Further testing with the breadboard circuit is needed.

The hardware version i soldered is a bit older than the plan.
As well as the software version.

The software is written in C with AVRStudio and WinAVR.
The main program consists of under 300 lines of code.
It uses 3132 bytes in the flash for code.
So there is plenty of room in the 8 kb flash for further extensions.
For the LCD i used the routines from Mikrocontroller.net.
(A big thanks to this side! It is just a paradise for µC users... at least when you can read german)
As soon as i figured out how to post software here i will upload it. ;)