Upload
others
View
8
Download
0
Embed Size (px)
Citation preview
Aml Abbas, Ali Darwish, Ehsanolah Hafezi, Fatima Zahra Doussi
Grupp 15 Slutrapport: Klocka
2019-05-21
Kurs: Digitala System (EITA15)
Handledare: Bertil Lindvall
Institution: Campus Helsingborg
1
Abstract The purpose of this project is to understand the communication between different components in digital systems. The task is to create and construct a prototype for a functioning system. Additionally, this project is about building a digital clock where the display shows the time with some text. The clock is based on three main components which are Real Time Clock( DS1307), the microcontroller(AT mega 1284) and an 16x2 Alfanumeric LCD dispaly.
2
1 Inledning 4 1.1 Syfte 4 1.2 Avgränsning 4 1.3 Rapportens disposition 4
2 Teori 5 2.1 Produktbeskrivning 5 2.2 Kravspecifikation 5 2.3 Hårdvara 5
2.3.1 Kopplingsschema: 5 2.3.2 Komponenter 6
Microcontroller 6 JTAG 6 LCD 6 Tryckknappar 6 Realtidsklocka 7
2.4 Mjukvara 7
3 Genomförande 7 3.1 Idéutvecklingen 7 3.2 Hårdvarukonstruktion 7 3.3 Mjukvarukonstruktion 8
4 Resultat 8
5 Utvärderande diskussion 8
6 Referenslista 9
7 Appendix 10 7.1 Kopplingsschema 10 7.2 Källkod 10
3
1 Inledning Projektet innehåller den mest viktiga delen av kursen Digitala System ( EITA 15). Syftet
med projektet var att konstruera en fungerande digital prototyp där mjukvaran
kommunicerar med hårdvaran. Projektet har valts efter diskussion med gruppen och
samråd med läraren. I denna rapport avhandlas en lätthanterlig klocka som innehåller
tiden och en kort text.
1.1 Syfte
Projektet syftar till att fördjupa sin förståelse om hur en konstruktionsprocess för en prototyp går till. Dessutom fördjupas förståelsen om den digitala kommunikationen mellan hårdvara och mjukvara samt kodning i C-programmering.
1.2 Avgränsning
Klockan har tagits fram efter de kriterier och krav som beskrivs under kravspecifikation.
1.3 Rapportens disposition
Rapporten sammanfattas i sju punkter. I första punkten ges en beskrivning av
prototypen och syftet med den. I andra punkten ges en kort beskrivning om produkten
och kravspecifikationen. Dessutom presenteras material som har använts vid
framtagandet av prototypen. I tredje punkten beskrivs metoden och utförandet i
detaljerad form. I nästa punkt redovisas resultatet. Därnäst diskuteras svårigheter som
dök upp under projektets gång men också hur de har åtgärdats. De två sista punkterna
innehåller referenser, källkod samt skisseringsschemat för produkten.
4
2 Teori
2.1 Produktbeskrivning
Produkten är en klocka som med hjälp av LCD, RTC och mikroprocessorn Atmega
1284 visar tid och text. RTC:n genererar tid och skickar den till processorn. Sedan
skickar Atmega datan vidare till LCD som visar det på skärmen. Dessutom visas en kort
text till höger om klockslaget.
2.2 Kravspecifikation
1. I början på första raden i LCD:n ska tiden visas i formaten “hh:mm:ss”.
2. I slutet på första raden i LCD:n ska texten “Time” visas.
3. Det ska finnas tre tryckknappar.
○ Första knappen (H): Timmarna ska ökas när H-knappen trycks.
○ Andra knappen (M): Minuterna ska ökas när M-knappen trycks.
○ Tredje knappen (S): Sekunderna ska ökas när S-knappen trycks.
4. AVR Atmega 1284 ska kunna avläsa data från RTC:n och kontinuerligt
presentera datan på displayen.
2.3 Hårdvara
RTC, virtråd, Virapparat, LCD alfanumerisk tecken-display, kristall, push-knappar,
mikrokontrollern Atmega 1284, potentiometer(0-5V), resistorer och prototypkort.
2.3.1 Kopplingsschema
Kopplingsschemat är en bas för hela projektet och visar hur de olika komponenterna
kommunicerar med varandra. Se bilaga 7.1
5
2.3.2 Komponenter
Komponenter som användes under arbetet beskrivs nedan. Informationen är hämtad
från databladet om varje komponent.
● Mikroprocessor
Mikrokontrollern som används i detta projekt är en ATMega1284 low-power AVR
8-bit. Processorn utför program i datorn och används till styrning och
programmering av kommunikationen mellan samtliga komponenter. Processorn
har 4 portar (A, B, C & D) och 40 pinnar, varav 32 är I/O pinnar som är
programmerbara.
● JTAG
JTAG är ett gränssnitt som med hjälp av den kan man köra, felsöka, debugga
och testa programmet.
● LCD Komponenten är en alfanumerisk display som kan skriva ut bokstäver och siffror
enligt ASCII. Displayen har två rader vardera med 16 tecken.
● Tryckknappar
Tre knappar används för att ställa in klockan genom att öka timmar, minuter eller
sekunder.
● Real Time Clock (RTC)
RTC:n som används är av typen DS1307. Den genererar tiden och skickar den
till LCD:n via processorn.
6
2.4 Mjukvara
Hela projektet är skriven i programspråket C i AtmelStudio 7 som är installerat på
universitetets datorn.
3 Genomförande
3.1 Idéutvecklingen Gruppen har kommit fram till att konstruera en textbaserad klocka. Sedan diskuterades
kraven på prototypen. När kravspecifikationen var färdigställd sattes arbetet igång med
att studera vilka hårdvarukomponenter som skulle vara passande. Därefter
preciserades kraven och när materialet var bestämt ritades ett skisseringschema.
Vidare diskuterades idén med handledaren som granskade samt godkände den.
3.2 Hårdvarukonstruktion
Efter att kopplingsschemat godkändes och granskades, kopplades komponenterna upp
på ett prototypkort. Virning och lödning användes för att sätta komponenterna fast på
kortet. För att säkerställa att hårdvaran var rättkopplad kopplades en lysdiod till
processorn.
3.3 Mjukvarukonstruktion
När komponenterna var färdigkopplade till kretsen påbörjades programmeringen. Innan
programmeringsdelen sattes igång, studerades databladet noga för de olika
komponenterna om hur de kommunicerar med varandra. Dessutom testades mjukvaran
med hjälp av en JTAG.
7
4 Resultat
Resultatet av projektet var en färdigställd klocka som fungerar enligt
kravspecifikationen, som ges under 2.2 Kravspecifikation.
5 Utvärderande diskussion
Slutligen lyckades gruppen att implementera idèn och få fram en fungerande prototyp.
Gruppen har mött flera svårigheter exempelvis kommunikationen med RTC:n. Det tog
över två veckor innan problemet hittades. Felet var att komponenten RTC inte
fungerade och det ledde till att data inte skickades till processorn. Gruppen trodde till en
början att det var koden som inte fungerade. Därför skrevs koden om och om igen utan
att få något vettigt resultat. Efter flera felsökningar kom gruppen på att testa koden med
en annan RTC och då upptäcktes att koden fungerade utmärkt.
En annan svårighet som gick till mötes under arbetets gång var att lysdioden inte lyste
när den kopplades till mikrokontrollern. Detta berodde på att processorn hade gått
sönder på grund av för hög matningsspänning. Därför byttes den mot en ny processor.
På kravspecifikationen ändrades knappfunktioner på grund av en bättre lösning som
ledde till en lätthanterbar klocka. Gamla kraven på knapparna var:
a. Första knappen (Options): Pekaren ska gå till hh, mm eller ss.
b. Andra knappen (Increase): Värdet där pekaren är ska ökas när knappen
trycks.
c. Tredje knappen (Decrease): Värdet där pekaren är ska minskas när
knappen trycks.
Den viktiga slutsatsen som gruppen kom fram till är att alltid testa samtliga komponenter
innan kodning och efter att koden inte har gett det önskade resultatet, förutsatt att
8
koden har skrivits om och ändrats flera gånger och ingen resultat har noterats. Därför
ska man ibland felsöka både hårdvaran och mjukvaran. Det kan hända att någon av
komponent på grund av felkoppling under arbete går sönder.
Det är också viktigt att utnyttja alla labbtillfälle för att hinna i tid. Eftersom felsökning kan
ibland kräva mycket tid och något oväntat kan hända med projektet.
6 Referenslista
● ATMega1248 High-Performance AVR 8-bit Microcontroller,
https://www.eit.lth.se/fileadmin/eit/courses/edi021/datablad/Processors/ATmega1
284.pdf
● Bilting, U.& Skansholm, J. (2011). Vägen till C. Lund: Studentlitteratur AB.
● DS1307- 12C RTC,
https://www.eit.lth.se/fileadmin/eit/courses/edi021/datablad/Periphery/RTC/DS13
07.pdf
● LCD Units Alfanumerisk teckendisplay,
https://www.eit.lth.se/fileadmin/eit/courses/edi021/datablad/Display/LCD.pdf
9
7 Appendix
7.1 Kopplingsschema
7.2 Källkod
//Main.c
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include "LCD.h"
#include "BUTTONS.h"
#include "I2C2.h"
#include "RTC2.h"
10
#define F_CPU 8000000L // CPU clock speed 16 MHz
#define F_SCL 100000L // I2C clock speed 100 kHz
void msDelay(int delay);
void InitAVR();
int main(void)
{
InitLCD();
CursorPos(0,0);
CursorBlink(1);
SendString("skarmen ar redo!");
InitAVR();
I2C_Init();
SetTime();
while(1)
{
incr_hour();
incr_minute();
incr_second();
WriteTime();
msDelay(1000);
}
}
void msDelay(int delay) // put into a routine
{ // to remove code inlining
11
for (int i=0;i<delay;i++) // at cost of timing accuracy
_delay_ms(1);
}
void InitAVR()
{
DDRB = 0b11111111; // 1111.1111; set B0-B7 as outputs
DDRC = 0b00000000; // 0000.0000; set PORTC as inputs
}
//----------------------------------------------------------------------------------------------------------------
//RTC.c
#include <stdint.h>
#include "RTC2.h"
#include "LCD.h"
#define rtc 0xD0 // I2C bus address of rtc RTC
#define SECONDS_REGISTER 0x00
#define MINUTES_REGISTER 0x01
#define HOURS_REGISTER 0x02
/**
#define RAM_BEGIN 0x08
#define RAM_END 0x3F
*/
uint8_t hours = 0x00;
uint8_t minutes = 0x00;
uint8_t seconds = 0x00;
12
void rtc_GetTime(uint8_t *hr, uint8_t *min, uint8_t *sec)
// returns hours, minutes, and seconds in BCD format
{
*hr = I2C_ReadRegister(HOURS_REGISTER);
*min = I2C_ReadRegister(MINUTES_REGISTER);
*sec = I2C_ReadRegister(SECONDS_REGISTER);
if (*hr & 0x40) // 12hr mode:
*hr &= 0x1F; // use bottom 5 bits (pm bit = temp & 0x20)
else *hr &= 0x3F; // 24hr mode: use bottom 6 bits
}
void SetTime()
// simple, hard-coded way to set the date.
{
I2C_WriteRegister(HOURS_REGISTER, hours); // add 0x40 for PM
I2C_WriteRegister(MINUTES_REGISTER, minutes);
I2C_WriteRegister(SECONDS_REGISTER, seconds);
}
void WriteTime()
{
ClrScr();
//uint8_t hr=0x01;
//uint8_t min=0x02;
//uint8_t sec=0x03;
rtc_GetTime(&hours,&minutes,&seconds);
13
LCD_TwoDigits(hours);
SendChar(':');
LCD_TwoDigits(minutes);
SendChar(':');
LCD_TwoDigits(seconds);
SendString(" Time");
}
void LCD_Time()
{
CursorPos(0,0);
WriteTime();
}
//----------------------------------------------------------------------------------------------------------------
// I2C.c
#include <util/twi.h>
#include "I2C2.h"
#define F_CPU 8000000L // CPU clock speed 8 MHz
#define F_SCL 100000L // I2C clock speed 100 kHz
#define TW_STOP 0x94 // send stop condition (TWINT,TWSTO,TWEN)
#define I2C_Stop() TWCR = TW_STOP // inline macro for stop condition
#define TW_START 0xA4 // send start condition (TWINT,TWSTA,TWEN)
#define TW_READY (TWCR & 0x80) // ready when TWINT returns to logic 1.
#define TW_STATUS (TWSR & 0xF8) // returns value of status register
14
#define rtc 0xD0 // I2C bus address of rtc RTC
#define TW_SEND 0x84 // send data (TWINT,TWEN)
#define TW_NACK 0x84 // read data with NACK (last uint8_t)
#define READ 1
extern uint8_t hours;
extern uint8_t minutes;
extern uint8_t seconds;
void I2C_Init()
// at 8 MHz, the SCL frequency will be 8/(8+2(TWBR)*4^), assuming prescalar of 0.
// so for 100KHz SCL, TWBR = ((F_CPU/F_SCL)-8)/2 = ((8/0.1)-8)/2 = 144/2 = 72.
{
TWSR = 0; // set prescalar to zero
TWBR = ((F_CPU/F_SCL)-16)/2; // set SCL frequency in TWI bit register
}
uint8_t I2C_Start()
// generate a TW start condition
{
TWCR = TW_START; // send start condition
while (!TW_READY); // wait
return (TW_STATUS==0x08); // return 1 if found; 0 otherwise
}
uint8_t I2C_SendAddr(uint8_t address)
// send bus address of slave
{
TWDR = address; // load device's bus address
15
TWCR = TW_SEND; // and send it
while (!TW_READY); // wait
return (TW_STATUS==0x18); // return 1 if found; 0 otherwise
}
uint8_t I2C_Write (uint8_t data) // sends a data uint8_t to slave
{
TWDR = data; // load data to be sent
TWCR = TW_SEND; // and send it
while (!TW_READY); // wait
return (TW_STATUS!=0x28); // return 1 if found; 0 otherwise
}
uint8_t I2C_ReadNACK () // reads a data uint8_t from slave
{
TWCR = TW_NACK; // nack = not reading more data
while (!TW_READY); // wait
return TWDR;
}
void I2C_WriteRegister(uint8_t deviceRegister, uint8_t data)
{
I2C_Start();
I2C_SendAddr(rtc); // send bus address
I2C_Write(deviceRegister); // first uint8_t = device register address
I2C_Write(data); // second uint8_t = data for device register
I2C_Stop();
}
16
uint8_t I2C_ReadRegister(uint8_t deviceRegister)
{
uint8_t data = 0;
I2C_Start();
I2C_SendAddr(rtc); // send device bus address
I2C_Write(deviceRegister); // set register pointer
I2C_Start();
I2C_SendAddr(rtc+READ); // restart as a read operation
data = I2C_ReadNACK(); // read the register data
I2C_Stop(); // stop
return data;
}
//----------------------------------------------------------------------------------------------------------------
// LCD.c
#include <avr/io.h>
#include <stdlib.h>
#include <util/delay.h>
#include "LCD.h"
#define DDR_LCD DDRB //Set Data direction for LCD
#define PORT_LCD PORTB //Set Port for Data Transfer in LCD
(Actual value of the port/pins)
#define DDR_Control_PORT DDRD //Set Data direction for control of LCD
(RS, RW & Enable)
17
#define LCD_Control_PORT PORTD //Set Port for control of LCD (RS,
RW & Enable) - (Actual value of the port/pins)
#define Enable 2 //Set Pin for Enable Switch// When we write data to
LCD, this pin is set to high. Otherwise low!
#define RW 1 //Set Pin for Read/Write Switch
#define RS 0 //Set Pin for Resistor Switch
char ColumnPosition[2] = {0, 32}; //Array to store the position of columns
uint8_t attributes = 0b00001110;
void CheckBusy()
{
DDR_LCD= 0x08; //Set Data Direction for
LCD to Input
LCD_Control_PORT|= 1<<RW; //Set LCD to Read Mode;
R/w pin High
LCD_Control_PORT&= ~1<<RS; //Set LCD to Read
Commands; RS pin Low
while (PORT_LCD >= 0x80) //Condition Checking; if
LCD sends back a value < 80 then it is busy
{
FlashLCD();
}
DDR_LCD= 0xFF; //Set Data Direction for
LCD to Output, for further operations
18
}
void LCD_Line(uint8_t row) // put cursor on specified line
{
CursorPos(0,row);
}
void FlashLCD()
{
LCD_Control_PORT|= 1<<Enable; //Enable Pin High
_delay_ms(5);
LCD_Control_PORT&= ~1<<Enable; //Enable Pin Low
}
void SendCmd(unsigned char cmd)
{
CheckBusy();
PORT_LCD = cmd;
LCD_Control_PORT&= ~ ((1<<RW)|(1<<RS)); //write mode; command mode
FlashLCD();
PORT_LCD = 0x00;
}
void SendChar(unsigned char character)
{
CheckBusy();
PORT_LCD = character;
LCD_Control_PORT&= ~ (1<<RW);
LCD_Control_PORT|= 1<<RS;
19
FlashLCD();
PORT_LCD = 0x00;
}
void SendString(char *str)
{
while(*str > 0)
{
SendChar(*str++);
}
}
void SendInteger(int value)
{
char ch[16];
itoa(value,ch,10);
SendString(ch);
}
void SendDecimal(double value, int width, int precision)
{
char ch[16];
dtostrf(value,width,precision,ch);
SendString(ch);
}
void DisplayOnOff(uint8_t value)
{
CheckBusy();
20
if(value==0)
{
attributes &= ~(1<<2);
SendCmd(attributes);
}
else
{
attributes |= (1<<2);
SendCmd(attributes);
}
}
void CursorOnOff(uint8_t value)
{
CheckBusy();
if(value==0)
{
attributes &= ~(1<<1);
SendCmd(attributes);
}
else
{
attributes |= (1<<1);
SendCmd(attributes);
}
}
void CursorBlink(uint8_t value)
{
21
CheckBusy();
if(value==0)
{
attributes &= ~(1<<0);
SendCmd(attributes);
}
else
{
attributes |= (1<<0);
SendCmd(attributes);
}
}
void CursorPos(uint8_t x, uint8_t y)
{
SendCmd(0x80 + ColumnPosition[x] + (y));
}
void InitLCD()
{
DDR_Control_PORT |= 1<<Enable | 1<<RW | 1<<RS;
_delay_ms(50);
SendCmd(0x01); //Clear Screen 0x01 = 00000001
_delay_ms(2);
SendCmd(0x38); //Selecting 8- bit Mode
_delay_us(50);
SendCmd(0b00001110); //Set attributes on 1st three bits:
{Display-ON/OF, Cursor-ON/OFF, Cursor-Blink-ON/OFF}
22
_delay_us(50);
}
void ClrScr(void)
{
SendCmd(0x01);
_delay_ms(2);
}
void LCD_TwoDigits(uint8_t data)
// helper function for WriteDate()
// input is two digits in BCD format
// output is to LCD display at current cursor position
{
uint8_t temp = data>>4; // get upper 4 bits
SendChar(temp+'0'); // display upper digit
data &= 0x0F; // get lower 4 bits
SendChar(data+'0'); // display lower digit
}
//----------------------------------------------------------------------------------------------------------------
//BUTTONS.c
#include<avr/io.h>
#include "BUTTONS.h"
#include "LCD.h"
#include "RTC.h"
23
#define DDRA 0x00;
#define PORT_hrButton PORTA;
void incr_hour(void){
PORTA=0b00000001;
if((PINA & PORTA) == 0 ){
hours++;
if(hours==36){
hours=0;
}
if(hours==10){
hours= 16;
}
if (hours==26){
hours=32;
}
SetTime();
WriteTime();
}
}
void incr_minute(void){
PORTA=0b00000100;
if((PINA & PORTA ) == 0 ){
minutes++;
if(minutes==89){
minutes=0;
}
if(minutes==10){
24
minutes= 16;
}
if (minutes==26){
minutes=32;
}
if (minutes==42){
minutes=48;
}
if (minutes==58){
minutes=64;
}
if (minutes==74){
minutes=80;
}
SetTime();
WriteTime();
}
}
void incr_second(void){
PORTA=0b00010000;
if((PINA & PORTA) == 0){
seconds++;
if(seconds==89){
seconds=0;
}
if(seconds==10){
seconds= 16;
25
}
if (seconds==26){
seconds=32;
}
if (seconds==42){
seconds=48;
}
if (seconds==58){
seconds=64;
}
if (seconds==74){
seconds=80;
}
SetTime();
WriteTime();
}
}
26