Olimex MOD-IO with ENC28J60 Module |
This entire project is hosted on the Olimex MOD-IO development board with the famous ENC28J60 Ethernet controller attached. Briefly, the ENC28J60 Ethernet controller is a very cost effective way to Ethernet enable low-cost, low-power 8-bit microcontrollers using the SPI bus.
The course made use of the TuxGraphics TCP/IP stack which is surprisingly easy to bring online. The ATmega16 CPU on this development board is not natively supported by the stack but only a few simple modifications are required to make it compile and load without warning. I was up and running in under an hour.
The Interface
One severe limitation of this hardware is the 1kB of RAM. This limits the response size to approximately 700 bytes. I could have broken up my responses into multiple parts but decided to keep all responses under the buffer size.
The Relay Control Homepage |
Here is the Makefile target that I use to minify, gzip and convert to a C header file the stylesheet used for this project. You can yell at me for using sed twice, I was in a hurry!
%.css.h: %.css
yui-compressor --type css $^ > $^.min
gzip -c $^.min > $^.gz
xxd -i $^.gz | sed -e 's/.\[\]\ =/\[\]\ PROGMEM\ =/g' | sed -e 's/unsigned/const/g' > $@
rm -f $^.gz $^.min
I have one of these for JavaScript and HTML (varies slightly) as well.
Uptime Counter
I have implemented 3 basic features. The first is the System Uptime counter. This is a simple struct residing on the microcontroller that keeps track of days, hours, minutes and seconds.
typedef struct {
uint16_t days;
uint8_t hours;
uint8_t minutes;
uint8_t seconds;
uint16_t millis;
} uptime_t;
I increment uptime once per millisecond in a timer compare match ISR. It would have been faster to just keep track of uptime in a uint64_t and then convert this into days, hours, minutes and seconds when required, but I like this approach.
void __attribute__((signal)) TIMER0_COMP_vect(void) {
if(++uptime.millis == 1000) {
uptime.millis = 0;
if(++uptime.seconds == 60) {
uptime.seconds = 0;
if(++uptime.minutes == 60) {
uptime.minutes = 0;
if(++uptime.hours == 24) {
uptime.hours = 0;
uptime.days++;
}
}
}
}
}
Uptime is served to the browser using JSON. This is fetched in JavaScript using an AJAX request. This results in a very efficient use of system resources. This system can handle 150+ hits per second on the dynamically generated JSON pages.
{"d":0, "h":0, "m":0, "s":9, "ms":754}
Total HTTP RequestsThis is a simple one. It simply counts the total number of HTTP requests. This is also served using JSON.
{"count": 35}
The "AVR Web Server" Section |
The next step was to control some hardware. I decided to parse out a URL with the format /rly$num$state where $num is a number between 0 and 3 and $state is either 'on' or 'off'. If the microcontroller receives this command, it will turn on or off the selected relay.
In addition to this basic relay control, I have implemented HTTP authentication. When a relay command is sent, the device is also expecting the authentication headers. If no authentication headers are sent, the browser will receive a 401 response.
Authentication Required |
I also have a relay status feature. Relay status is served using yet another JSON request.
Hardware with Programmer/Debugger Attached |
Setup Overview |
The number of possible use cases for hardware like this is unbounded. I may end up using it to control my homebrew fume extraction system, but that is a another blog for another day.
If you have any questions or comments, leave them below. Thanks for reading!
No comments :
Post a Comment
Note: Only a member of this blog may post a comment.