Full Version : Daniels & Hartranft AVR Web Interface
avr >>COMMUNICATIONS & WEB PROJECTS >>Daniels & Hartranft AVR Web Interface


Admin3- 04-18-2006
Web-based AVR Interface by Marc Daniels & Scott Hartranft


Introduction
In the vein of today's trends to embed networking cababilities into simple appliances, our project implements a webpage interface for the Atmel AVR microcontroller. One of the original motivations of this project was to develop a low-level network interface for the Atmel device, specifically by controlling an ISA network card (see the eAVR Project) to transmit UDP packets across the Internet. We greatly modified our original plans once we found out about the SitePlayer device:


"World's Smallest Ethernet Web Server"


This board features a Crystal Semiconductors CS8900 Ethernet controller and on-board Flash memory to host a small webpage. Its extremely small footprint makes this device ideal for a embedded systems applications such as ours. It also uses a simple serial interface, which we've connected to the Atmel ATS8535 mcu. The major challenge of this project was to design code that gathers data from our sample peripheral devices (appliances) and formats and outputs to the SitePlayer's webpage.


--------------------------------------------------------------------------------

High level design
Our materials for this project included:

Atmel ATS8535 microcontroller
STK200 evaluation board (spec sheet pdf)
SitePlayer Ethernet Webserver device (spec sheet pdf)
8-digit LCD display for on-site monitoring at the mcu.
Crossover Ethernet connection or other connection for the SitePlayer
Null Modem cable for mcu-SitePlayer serial link
Any parts needed for the attached peripherals
The general scheme of our program's execution is that of a primitive command interpreter. We have a set of commands that will perform I/O on the Atmel's peripherals: a set of LEDs, a temperature sensor and fan (from Lab 6), a photodiode room-light indicator, and an IR security beam. The IR beam can be used to trigger an open door and is currently configured with a debouncing state machine to increment a room-occupation counter.
The following summarizes which commands the Atmel will support:

- status: Returns the status of the SitePlayer web interface.
- greenled[on/off]: Toggles the Green LED on the SitePlayer
- redled[on/off]: Toggles the Green LED on the SitePlayer
- led[X], 0 < X < 6: Toggles the Xth led on the STK eval. board.
- gettemp: Returns the current room temperature, per temperature module.
- lights: Returns the status of the room lights, per photodiode.
- fan[on/off]: Toggles the fan, which cools the temperature module.
- door: Returns the current room-occupancy counter, per IR security beam.


If a command is mistyped, or an input is erroneous, the Atmel will return "badCmd!" to the LCD monitor and a "Syntax Error" output to the webpage.



--------------------------------------------------------------------------------

Program/hardware design
The first major task we faced was sending and receiving data from the 8535 to the SitePlayer. We used the SitePlayer Software manual to understand the technical details of serial transfer to this device. Basically, each I/O operation takes 2-4 bytes: A command byte (like Read or Write with address length specification), an address byte or two (depending on whether we're addressing data in the higher regions of RAM), and the actual byte of data. For example, the printf commands below tell the SitePlayer to set the IP address to 128.84.235.244:

printf("%c",0x93); // Command byte: Write 4 bytes using two-byte addressing
printf("%c%c",0xE6,0xFF); // Address byte: Begin writing at 0xFFE6
printf("%c%c%c%c",128,84,235,244); // Data: 128,84,235, and 244 (the IP address)


Now, we just needed to specify memory areas on the SitePlayer for the input command (16 bytes) and output result (32 bytes). Our program used the Timer1 overflow interrupt to poll the region of SitePlayer memory corresponding to the webpage input. So once we receive something other than 0's, we do our command matching and carry on with the specific job. In each command we produce two output strings, one for the webpage (32 characters) and one for the chip-side LCD monitor (8 characters). For the actual serial transfers to and from the SitePlayer, we employ the UART receive interrupt. Also, the details about how to configure intial memory mappings for HTML variable names involve using the proprietary SitePlayer software to compile .spi configuration files, the details of which can be found here.

For two of our peripherals, we used the 8535's on-board ADC. Since we were using a gain of 4 on our temperature module, conversion to the actual temperature was just a simple division by 10 (the ADC discriminates on intervals of 4 mV). Also, we found it necessary and convenient to set up our temperature and Infrared data collection on a polling loop basis. This way, when a gettemp or door command is received, we need only to check a register value, not carry out the entire analog conversion. Also, the IR module has a 1-second debouncer, so if it were used on a door, the beam must be interrupted for over 1 second before the occupancy counter is incremented. Also, we only want to increment this counter once per beam interruption--this is another feature we decided to build into the IR module.



--------------------------------------------------------------------------------

Results of the design
Originally, we had planned on implementing an ethernet board that would have been capable of sending and receiving full UDP packets. Instead, once given the SitePlayer to use as a basis, we were able to implement all of the "telnet-like" functionality, which we had set out to implement.
We did have some minor bugs in the actual display of result of the telnet commands, since we did not implement a true telnet interface. Since the web page simultaneously sends the new command to the input variable and reads the "output" from the output variable in its memory, it is usually displaying the result of the previous command, until the page is refreshed. However, we feel this is a minor bug, as the page will reload itself after 5 seconds anyway. Also, the Atmel often runs so fast that this bug is not always seen.

Our worst problems and most time spent were getting the SitePlayer to recognize the fact that it should talk to a computer. There were many times when, even with an IP programmed into the SitePlayer, the accompanying PC would not talk to it. Also, occasionally when we programmed the Atmel chip the SitePlayer would hang up due to the serial cables being connected. This would cause the need for a hard reset of the SitePlayer, and occasionally, a reprogramming of its IP through the serial port. We had far more problems in the lab than when we actually placed the SitePlayer on a real network, however - we do not have an explanation for that behaviour.

Overall we were pleased with the control we had. Our design was also very modular, so adding further components or replacing existing ones is quite simple. Anything that the atmel can control on its pins can be controlled by our system, but adding another case in the code to look for the telnetted control word. As a result, once we had the first word working, we were able to add most of the rest of our devices in only a few hours.



--------------------------------------------------------------------------------

What you would do differently next time?
For the future, we would have had a real network connection, somewhere exterior to the Phillips lab, which has a very unreliable network and even less reliable computers. Having a stable network connection would have made debugging much easier. Also, we would like to see if it would be possible to use a standard telnet program to connect to the SitePlayer. This would have involved some heavy modification of the SitePlayer however, and may not have been possible.

We also would have liked to implement a simple FTP interface to the SitePlayer/Atmel. There is sufficient RAM on board the development board to allow such a task, but we did not have time to work out the transfers. It would have involved adding another command, and returning the contents of the RAM to a variable on the SitePlayer. There is very limited space for variable on the SitePlayer, only about 760 bytes worth, but we may have been able to find a way to store the files in the traditional web pages section of its memory.


Link:
http://instruct1.cit.cornell.edu/courses/e...ts/s2001/mrd19/

CODE

#include 90s8535.h
#include stdio.h  
#include lcd.h
#include string.h              
 
#define MAX_IN_LENGTH  16
#define MAX_OUT_LENGTH  32
#define timer_control  0x04
#define ADC_control  0xC5  //ADEN=1, ADSC=0, ADFR=0, ADIF=0,
     //ADIE=0 (No interrupts)          
//Prescale = 101: 4MHZ/32 = 125KHz
#define OPEN 1
#define CLOSED 0

char door_state = CLOSED;

char i=0, j=0;
char new_key[16];      
char output[16];
char textout[MAX_OUT_LENGTH];
char lcd_buffer[17];          
char update=1;
char hold;
int people;
char debounce;

int door;
int voltage;    //input voltage
int voltage_temp;
char light_inten;
float temp;        

#define reload1 65400
void init(void);
void clear_input(void);
//**********************************************************
//this interrupt is triggered when a character is received into the serial port input buffer
interrupt[UART_RXC] void keyboard_interrupt(void) {
//we only want to read the whole input, which we know to be 16 bytes long
//so we loop until we have a full buffer
new_key[i] = UDR;
if(UDR == 0)
 new_key[i] = 0;

i++;
//once we have a full buffer, we try to match the input to a known command
if(i==16){
 new_key[16] = 0;
 i=0;  
 //test to see if everything is working normally
 if(!strncmpf(new_key, "status", 6)){      
  strcpyf(textout, "System working.");
  strcpyf(output, "sys up");
  clear_input();
 }                    
 //turn on and off LEDs on the Development board      
 else if((!strncmpf(new_key, "led", 3)) && (new_key[3] > 47) && (new_key[3] &60; 54)){      
  PORTB = PORTB ^ (0x01 leftshift (new_key[3] - 48));
  strcpyf(output, "LedDone");  
  strcpyf(textout, "LedDone");  
  clear_input();
 }  
 //Turn on the Red Led on the SitePlayer board
 else if(!strncmpf(new_key, "redledon", 8)){      
  strcpyf(output, "RedLED1");
  strcpyf(output, "Red Led is On");
  printf("%c",0x90);
  printf("%c%c",0x14,0xff);
  printf("%c",0x00);
  clear_input();
 }                            
 //Turn on the Red Led off the SitePlayer board
 else if(!strncmpf(new_key, "redledoff", 9)){      
  strcpyf(output, "RedLED0");
  strcpyf(textout, "Red Led is Off");
  printf("%c",0x90);
  printf("%c%c",0x14,0xff);
  printf("%c",0x01);
  clear_input();
 }                        
 else if(!strncmpf(new_key, "greenledon", 10)){      
  strcpyf(output, "GrnLED1");
  strcpyf(textout, "Green Led is On");
  printf("%c",0x90);
  printf("%c%c",0x15,0xff);
  printf("%c",0x00);
  clear_input();
 }                            
 else if(!strncmpf(new_key, "greenledoff", 11)){      
  strcpyf(output, "GrnLED0");
  strcpyf(textout, "Green Led is Off");
  printf("%c",0x90);
  printf("%c%c",0x15,0xff);
  printf("%c",0x01);
  clear_input();
 }      
 //Retrieve the current temperature reading
 else if(!strncmpf(new_key, "gettemp", 7)){
  sprintf(output, "Temp: %-i",(int)temp);
  sprintf(textout, "Temperature: %-i degF",(int)temp);
  clear_input();
 }          
 //Check to see how many times the IR beam has been tripped
 else if(!strncmpf(new_key, "door", 4)){
  sprintf(output, "Ppl: %-i",people);
  sprintf(textout, "People counter = %-i",people);
  clear_input();                            
 }
 //Check to see if it is dark in the room
 else if(!strncmpf(new_key, "lights", 6)){
  if (light_inten > 75) {
   sprintf(output, "LghtsOn");
   sprintf(textout, "Lights are On");
  } else {
          sprintf(output, "LghtsOff");
   sprintf(textout, "Lights are Off");
  } clear_input();
 }                    
 //Turn Fan on, for use with the thermometer
 else if(!strncmpf(new_key, "fanon", 5)){  
  strcpyf(output, "Fan On");
  strcpyf(textout, "Fan is now On.");
  PORTB = PORTB | 0x40;
  clear_input();
 }
 else if(!strncmpf(new_key, "fanoff", 6)){  
  strcpyf(output, "Fan Off");
  strcpyf(textout, "Fan is now Off.");
  PORTB = PORTB & 0xBF;
  clear_input();
 }
 else if(new_key[0] == 0) {}
 //if nothing else, bad syntax
 else{
  strcpyf(output, "badcmd!");
  strcpyf(textout, "Syntax Error");
  clear_input();
 }                    

 //Send result to the SitePlayer, one byte at a time, to be safe  
 if(update){
  for(i=0;i &60; MAX_OUT_LENGTH;i++){
   printf("%c",0x80);
   printf("%c",(MAX_IN_LENGTH+i));
   printf("%c",textout[i]);
  }
  i=0;
       
 //Update the command displayed on the local LCD
         lcd_clear();
  lcd_gotoxy(0,0);
  sprintf(lcd_buffer,"%s",output);
  lcd_puts(lcd_buffer);  
  update = 0;
 }  
}
}  

interrupt[TIM1_OVF] void quartersec(void) {
//Blink a light to know we're alive
PORTB = (PORTB ^ 0x80);
TCNT1 = reload1;

//Constantly request latest value of "Input" variable on the SitePlayer
printf("%c",0xCf);
printf("%c",0x00);

//examine door setting
ADMUX = 1;          
ADCSR = ADC_control;            
while ((ADCSR & 0x40) == 0x40) {}
ADMUX = 1;          
ADCSR = ADC_control;            
while ((ADCSR & 0x40) == 0x40) {}
door = ADCL;
hold = ADCH;
 
if (door_state == OPEN) {
 if (door &60; 2) { // door is still open...
    if (debounce++ == 30) {
      people++;
      PORTB = (PORTB ^ 0x01);
    }
 }
 else {
    door_state = CLOSED;            
         debounce = 0;
          }
} else if (door &60; 2) door_state=OPEN; // door was last closed, check if it's open now


//always measure temp
ADMUX = 0;
ADCSR = ADC_control;
while ((ADCSR & 0x40) == 0x40) {}
ADMUX = 0;
ADCSR = ADC_control;
while ((ADCSR & 0x40) == 0x40) {}
voltage_temp = ADCL;
voltage = ADCH;
voltage = voltage_temp | voltage shift left 8;
// print out voltage
temp = voltage / 10.0;              

//always measure light intensity
ADMUX = 5;
ADCSR = ADC_control;
while ((ADCSR & 0x40) == 0x40) {}
ADMUX = 5;
ADCSR = ADC_control;
while ((ADCSR & 0x40) == 0x40) {}
light_inten = ADCL;
hold = ADCH;

}

//This function will blank out the Input variable on the Siteplayer, so we don't keep
//running the same command repeatedly
void clear_input(void){
update = 1;
       for(i=0;i &60; MAX_IN_LENGTH;i++){
 printf("%c",0x80);
 printf("%c",i);
 printf("%c",0);      
}              
i = 0;
}

void init(void)
{
DDRB = 0xff;  //setup LEDs
PORTB = 0xff;  
DDRD = 0xff; //setup Serial port
TIMSK = 0x04;
TCCR1B = 0x05;
TCNT1 = reload1;

//more serial port setup
UCR = 0x90 + 0x08;
UBRR = 25;
     
//LCD on port C
#asm              
    .equ __lcd_port=0x15
#endasm

lcd_init(16);
lcd_clear();
lcd_gotoxy(0,0);
sprintf(lcd_buffer,"init");
lcd_puts(lcd_buffer);    

ADMUX = 1;
ADCSR = ADC_control;
// disable Analog comparator
ACSR = 0x80;    
       
people = 0;          

// set IP on SitePlayer
printf("%c",0x93);
printf("%c%c",0xE6,0xFF);
printf("%c%c%c%c",128,84,235,244);

#asm
 sei
#endasm    
}          

void main(void)
{
init();
while(1) {}
}






Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.