Avatar billede mithra Nybegynder
13. maj 2003 - 21:00 Der er 16 kommentarer

programmering til display fra analog til digital

Jeg er i gang med programmering af kit 80385 til aflæsning af en analog luxmeter som måle 0 volt ved 0 lux og 5 Volt ved 5000 Lux.
Kitet er udstyret med et display som skal aflæse disse værdi digital og vise text.
der anvendes programering "system 51W" i C.
Any idea about how I should proceede?
Kittet tilsluttes et stationær PC og en strømforsyning med +12V -12V og +5V.
Med Venlig Hilsen,
Mithra
Avatar billede mithra Nybegynder
13. maj 2003 - 21:01 #1
Svaret kan sendes direkte på: sophie@nostromo.dk
Avatar billede madd Nybegynder
13. maj 2003 - 21:04 #2
Taget fra regelerne 2.1.13:

Det er ikke tilladt at...
.. tildele point for en opgave løst uden om Eksperten (feks. opgaver løst via mail, icq eller telefon).

/mattias
Avatar billede disky Nybegynder
13. maj 2003 - 21:08 #3
du aflæser en Adc ingang, og omregner værdien til lux og viser det i displayet-
Avatar billede mafiltenborg Nybegynder
19. maj 2003 - 09:48 #4
Uden at kende til hardwaren eller nogetsomhelst, har jeg da en bette kommentar og tilføjelse til disky's fine opskrift. Jeg tillader mig at antage at dit "kit" består af et (LCD?)-display som kan udlæse tal og en mikrocontroller af 8051-typen som kan programmeres fra din PC - og så noget krimskrams til strømforsyning mv.
1) Du sætter processoren op (er der f.eks. en vagthund som skal klappes?)
2) Beslut dig for hvordan du vil konstruer programmet. Jeg antager at apparatet skal opdatere displayet med jævne mellemrum, og så ser jeg to muligheder som "ligger lige til højrefoden":
2a) Enten en stor løkke, som:
Først sætter ADC'en i gang med at konvertere den analoge spænding fra din fotocelle og så venter på resultatet (ADC'er tager altså tid om at finde en digital værdi som udtrykker signalets størrelse).
Dernæst beregner løkken hvad der skal stå på displayet - ADC'en afleverer jo bare et tal, som lige skal omregnes til Lux.
Så skal tallet udskrivet på displayet. Dette kan faktisk være en hel opgave i sig selv, for displays er sjældent særlig "kloge". Typisk skal man hive og trække i nogen IO-pins, sætte sine data ud på en port og så hive i nogen flere IO-pins. Først da dukker tallet op på displayet.
Så bør løkken indeholde et stykke ventetid. Dette fordi displayet ellers vil blive opdateret i et rasende tempo, og så typisk komme til at flimre noget.
Og så begynder løkken forfra :)

2b) Alternativt kan du prøve dig frem med en timer- og interrupt-baseret løsning. Mere krævende, men osse mere spændende!
Her består programmet af tre dele: et hovedprogram indeholdende opsætning/initialisering af en timer (8051'eren har indbygget et par timere som kan sættes til f.eks. automatisk at generere interrupts med jævne intervaller) og ADC'en - og så en tom løkke. Hovedprogrammet har derpå intet andet formål end at spilde processorens tid, mens den venter på interrupts.
De to resterende dele er interrupt-service-rutiner for timeren og ADC'en.
Fidusen er at timeren - når den løber ud - forårsager at Timer-interrupt-rutinen afvikles. Denne rutine sætter så ADC'en op til at foretage en konvertering på en given indgang og generere et interrupt, når *den* er færdig.
Når så ADC'en en gang bliver færdig med at konvertere, genererer den (som vi jo satte den op til) et interrupt der forårsager at ADC-interrupt-rutinen afvikles. ADC-interrupt-rutinen består så af en beregning af resultatværdien og en skrivning til displayet.
That's it :) Ligesom dominobrikker der vælter hinanden.
Processen gentages så med det interval man har sat timeren op med.

Der findes masser af måder at løse opgaven på, så bare prøv dig frem. Der findes ingen direkte *forkerte* løsninger (hvis altså bare du får dimsen til at gøre det du vil ha' den til) - kun mere eller mindre smarte/snedige måder at nå resultatet på :)

Enhver som har opdaget mikrocontrollerens evner til at behandle/generere procesdata, vil for tid og evighed kun have et skævt smil tilovers for PC'ens evner udi samme disciplin - forudsat at vi holder os til user mode, hvor operativsystemet passer på os. Snakker vi kernel-mode hjælper det noget på sagen. Imidlertid er programmering i kernel-mode kun for de modige. Ligesom at gå på line henover en gylletank; Går det godt, er det godt. Går det skidt, er det noget lort ;)
Avatar billede karmapolice Nybegynder
19. maj 2003 - 10:06 #5
Inden jeg starter, så lad mig lige fortælle at det er 9 semestre siden at jeg legede med sådan et board. Men jeg kan da huske det vigtigste i grove træk.

Du kan nok fra starten af indstille dig på at kode det meste i assembler. Måden at komme i gang på er, at lave en .c fil med tomme funktioner og så compile disse til assembler. Derfra arbejder du så videre med assembler-filen.

For at skrive ud på displayet må du læse manualen. Det er noget med at styre en adresse på boardet og så skrive en ASCII-værdi ud som så gemmes på displayet.
Jeg vil nok foreslå løsningen ovenfor med at sætte et timer-interrupt op (læs igen manualen - til dette er der nok et helt eksempel) som læser ind et par gange i sekundet og skriver ud. Boardet kører vist 50MHz så du skulle have rigeligt tid mellem hver læsning til at omregne fra bin2ascii...Jeg har nogle assembler funktioner liggende til dette, hvis du vil have dem?
Avatar billede disky Nybegynder
19. maj 2003 - 10:22 #6
karma:
Hvorfor skulle man dog lave det i assembler ?

Man bruger normalt kun assembler til tidskrævende operationer, hvor C/C++ ikke er hurtig nok.
Avatar billede karmapolice Nybegynder
19. maj 2003 - 10:33 #7
Øhh...disky

Jeg ved slet ikke hvor jeg skal starte!

For det første så bruger man ikke C++ til at kode microcontrollere med! Til 80385eren kan man kode i C fordi de har lavet en compiler fra C til 80385 assembler.

For det andet så skal man sætte interrupt-registret op og tilgå adresser på boardet som alt andet lige både ER mere elegant og SER mere elegant ud i assembler.

For det tredie bruger man kun C til større programmer, hvilket man ikke kan sige at dette er. Og selv i dette tilfælde ville man være nødt til at skrive flere dele af koden i assembler for bl.a. at styre interrupts.

I bund og grund er det nok en smagssag på nogle områder men hvis man vil kode til en microcontroller så må man simpelthen ikke være bange for assembler...
Avatar billede mafiltenborg Nybegynder
19. maj 2003 - 10:36 #8
50 MHz? Lyder ikke umiddelbart som en 8051'er...Jeg har nok taget fejl.

Noget undrer mig dog: Hvorfor overhovedet anvende assembler?

Det lader sig helt fint gøre at lave interruptdrevet multikanal-ADC med aktiv noisecancelling, scanne keyboards, drive et stort LCD med grafik og menusystemer, vedligeholde data (inkl. sliding-window averaging og alt muligt andet) og samtidig køre noget regulering (uden at anvende floating points nogetsteds) - uden at få sved på panden, og i ren C, aldrig en eneste linie assembler...

Vel at mærke på en 1 MIPS 8-bit mikro.

Så hvorfor assembler? Vi snakker vel stadig mikrocontrollere, hvor begrebet "operativsystem" glimrer ved sit fravær, eller hvad?

Med dén der 50-MHz-raseri-cpu burde det da intet problem være at lave et par hundrede - eller tusinde - konverteringer i sekundet (i C), og så opdatere displayet sådan passende så det ikke blafrer alt for meget.

Hvorfor assembler?
Avatar billede karmapolice Nybegynder
19. maj 2003 - 10:43 #9
...fordi assembler er fedt
Avatar billede disky Nybegynder
19. maj 2003 - 10:44 #10
pkt 1:
Korrekt man måske ikke kan finde en C++ compiler, men jeg skrev C/C++, hvilket betyder en af delene !

pkt 2:
Det er ikke mere elegant i assembler.
Jeg er selv uddannet svagstrømsingeniør så jeg har prøvet rigeligt embeddet udvikling også til 80535 cpu'en, inklusivt til selv designede boards.
Og selv interrupt styring og opsætning osv, bliver normalt lavet i C eller andre sprog, dog ikke assembler.

pkt 3:
Jeg ved ikke hvor du har lært at udvikle embeddet software, men selv til små ting bruger man normalt C programmer, ganske enkelt fordi chancerne for fejl er mindre og udviklingstiden er kortere.
Interrupts osv, kan man uden problemmer lave i C.

Det man gør er f.eks.:
void IntTimer50ms( void ) interrupt 1 using 1
{
    INTflag = true;                // interrupt sket

    TL0 = 0xFF;                // TL0 + TH0 = 19455 = 50 ms
    TH0 = 0x4B;                   
}

Ved at bruge en ordentlig compiler, som i dette tilfælde var Kyle C Compiler, så kan registrene sættes direkte som det ses i ovenstående eksempel.

Altså ingen grund til at skulle rode med assembler.

p.s. Jeg er absolut ikke bange for assembler, jeg har udviklet rigeligt med assembler programmer og utilities på 6502,6510 og MC680x0  serierne. Senere også til Arm-7 og Arm-9. Men i dag bruger man kun assembler når de sidste microsekunder betyder meget.

Selvfølgelig er det smag og behag, men ingen grund til at gøre tingene sværere end de er.
Avatar billede karmapolice Nybegynder
19. maj 2003 - 10:45 #11
Ups, og så har jeg lige dobbeltchecket min hukommelse. Det board jeg kodede til var 12MHz og havde 32kb prom og 8kb ram.
Avatar billede disky Nybegynder
19. maj 2003 - 10:46 #12
karmapolice:
Din sidste kommentar sætter tingene i perspektiv, du udtaler dig udelukkende subjektivt, og har helt glemt at vurdere tingene objektiv.
Avatar billede disky Nybegynder
19. maj 2003 - 10:46 #13
okay næst sidste kommentar :)

p.s. Selv på 12MHz med ram og rom er der ingen grund til assembler.
Avatar billede mafiltenborg Nybegynder
19. maj 2003 - 11:13 #14
Disky:
Jeg mener du har så inderlig ret i dine betragtninger over behovet for assembler. Jeg sidder med en fornemmelse af at spørgeren er i en læreproces, så det gælder om at holde abstraktionsniveauet oppe. Her har højniveausprog en naturlig fordel. Det gælder om at holde koden overskuelig og letlæselig. Her (mener jeg) har højniveausprog en naturlig fordel. Der er intet behov for at klemme de allersidste mikrosekunder ud af processoren. Og jeg tvivler på at Mithra har pladsproblemer - hvilket assemblerfolkene altid fremfører som argument for fidusen ved programmering på det bare metal. Det fylder mindre... Sikkert nok, men kun hvis man er *seeej* til at programmere på det bare metal og kender alle smutvejene. Det gør de færreste, hvilket afspejles af mine egne erfaringer med at portere sådan noget lav-abstraktionsniveau-kode til et format mit lille hovede kan kapere. Det er uden videre muligt at reducere koden til halv størrelse og få mere fart. Og mere overblik, hvilket jo var den primære begrundelse for at lave det samme arbejde een gang til.
Problemet ligger ikke i assembler eller ej, men i at der ikke er så mange der magter at gøre det rigtigt. Det er simpelthen svært.
Hvilket Mithra ikke har brug for. Mithra har nok mere brug for at forstå principper og kunne opdele sit projekt i logiske bidder som setup, sekvens, LCD-handling og ADC-handling. Hvilket IMHO indikerer højniveausprog.

Selv på 32 KHz med 512 byte flash og 64 byte RAM er der ingen grund til assembler ;) Ihvertfald ikke når sigtet er læring og principper.

Slut for nu!
Avatar billede disky Nybegynder
19. maj 2003 - 12:00 #15
mafiltenborg:
Jeg takker og bukker :)
Avatar billede dan_magnus Nybegynder
23. maj 2003 - 00:57 #16
Lidt c code til Siemens 80535 up.
Sådan gør man det, her er også andre nyttige sup's der kan benyttes til 80535 Kittet. Alt er lavet af mig, og må benyttes frit. Delay funktion er designet til et 11,059MHz XTal.
'main' i dette exempel er bare noget lal til at teste med, se bort fra den, det skal du jo selv lave.
Jeg kan ikke huske hvilken c compiler jeg brugte.
Husk på at code og hardware forbindelser skal tilpasses.
Du skal først lave noget analog elektronik der kan omdanne lys til spænding 0..5Vdc. Som ledes til en af ialt 8 analoge input på 80535, her kan du vælge at converter i enten 8 eller 10 bit, derefter kan du manipulere med værdien som du vil i coden, måske indbygge liniarisering for compensation af den analoge del, eller noget med alarmer, og,og,og derudaf.
NB:Det er første gang jeg svare her på Experten, jeg hved ikke hvordan man vedhefter et dokument så det er synligt for alle.
mvh Dan



#pragma code= 0x4000 //{$M $4000 $0} offset addr
#pragma model=large; // Ext RAM       
// Program til 80535 Kittet. Benyttes til udvikling 
// Sidste revidering, 29-AUG-1998.Dan Nielsen       
// ################################################# 
// I dette program er der benyttet lysdioden på 
// 80535 kittet. Lysdioden er forbundet til p5.6 
// Port 4 er benyttet til et LCD display, Port 4 er data.
// P5.0=LCD(RS),P5.1=LCD(R/W),P5.2=LCD(E).
// Interrupt0 ben p3.2 er,forbundet til en tryk swits til gnd.
// RS232 seriel porten. Der er ingen handshake på   
// serielport. Seriel com er sat til 1-Startbit,     
// 1-stopbit, 8-Databit, 9600-Baud.                 
// *********** PROGRAM NAVN START.C ****************
// ========================================================
// Benyttede globale moduler
// --------------------------------------------------------
//#define __PRINTF__
#include <stdio.h>
//#include <string.h>
//#pragma data =0x800;
#pragma parameters=xdata;//compiler directive hardware har ext RAM
// --------------------------------------------------------
// ========================================================
// Preprossor definitioner
// --------------------------------------------------------
#define ESC      27
#define TRUE      1
#define FALSE      0
#define LED    P5.6  //Led på Kit
#define MAX    1200  //Tabel maximale længde
#define LCD_E  P5.2  //LCD styre signal "Enable" LCD pin 6
#define LCD_RW  P5.1  //LCD styre signal "Read/Write" LCD pin 5
#define LCD_RS  P5.0  //LCD styre signal "Register Select" pin 4
#define LCDPORT  P4  //LCD Data  "8 bit Data " LCD pin 7..14
#define DISPLAY  16  //LCD antal karaktere pr række
// ------------ --------------------------------------------
// ========================================================
// Functions prototyper
// --------------------------------------------------------
//  Timer 1 interrupt, benyttes til RS232 Baud-rate generator
void inctimer          (...);  // Timer0, benyttes til delay
void delay              (unsigned int);  // Delay i msek
void inter0            (...);  // Interupt0, P3.2
void inter1            (...);  // Interupt1, P3.3
void init              (void); // Global samling af initialisering
void ok                (void); // hjælpe test af programmering   
void Inte_rupt_init    (void); // initialiser interupt
void polling_int        (void); //skal gennemløbes jævnligt
void serial_init_9600  (void); // RS232 Seriel initialicering
void serial_init_19200  (void); // RS232 Seriel initialicering
void serial_init_57600  (void); // RS232 Seriel initialicering
void newline            (void); // RS232 retur og linie skift
void txbyte            (unsigned char); // RS232 Sender en byte seriel
unsigned char rexbyte  (void);          // RS232 modtag en byte seriel
unsigned char adc8bit  (unsigned char); // A/D, 8-bit  one meas
unsigned int adc10bit  (unsigned char); // A/D, 10-bit two meas
unsigned int volt      (unsigned int);  // A/D, fra int til spænding
void lcd_init          (void);          // LCD-Funktioner Initialiser LCD
void lcd_command        (unsigned char); // LCD-Funktioner comand to LCD
void lcd_data          (unsigned char); // LCD-Funktioner data til LCD
void lcd_busy          (void);          // LCD-Funktioner busy flag
void lcd_pos            (unsigned char); // LCD-Funktioner position
void lcd_dansk          (void);          // LCD-Funktioner Danske tegn
void lcd                (unsigned char*);// LCD-Funktioner skriv til LCD
unsigned char* ord      (unsigned int);  // ordiner value of int to string
// --------------------------------------------------------


// ========================================================
//  Globale Konstanter lagt i ROM 
// --------------------------------------------------------
// Tabel for Analog to Digital 10 bit converter function, in ROM
// adc10bit        range[    0  , 1  , 2  , 3  , 4  , 5  , 6  , 7  ]
const unsigned char range[]={0x00,0x40,0x62,0x84,0xA6,0xC8,0xEA,0x0C};

// Tabel for Dansk tegnsæt, pladseres i ROM
const unsigned char dansk[]=
  {
  0x1f,0x14,0x14,0x1f,0x14,0x14,0x17,0x00, // Æ
  0x01,0x0e,0x13,0x15,0x19,0x0e,0x10,0x00, // Ø
  0x04,0x0a,0x0e,0x11,0x1f,0x11,0x11,0x00, // Å
  0x00,0x00,0x1e,0x05,0x1f,0x14,0x0f,0x00, // æ
  0x00,0x00,0x01,0x0e,0x0a,0x0e,0x10,0x00, // ø
  0x04,0x0a,0x0e,0x01,0x0f,0x11,0x0f,0x00  // å
  };

// ========================================================
//  Globale variable 
// --------------------------------------------------------
bit                    int_0  ;  //: Boolean; INT0 kontrol Bit
bit                    int_1  ;  //: Boolean; INT1 kontrol Bit
xdata unsigned char    rx_byte ;  //: byte;    RAM
unsigned int            taeller ;  //: word;    idata
xdata bit              stopbit ;  //: Boolean; RAM
xdata unsigned int      sec,frac;  //: Delay variabel i RAM
xdata unsigned int      delayfrac; //: Delay variabel i RAM
xdata unsigned int      tael,pp ;    //: Word; universal variable
xdata unsigned char    tabel[MAX+2]; //: Global tabel 8bit
// --------------------------------------------------------



// ########################################################
// ########################################################
main()
{       
  init();
  lcd_init();
  while (!stopbit)
  {
      polling_int();
      delay(22);
        pp=adc10bit(0);
        printf("%8.u",pp);
        lcd_pos(3);
        lcd("æøåÆØÅ");
        lcd_pos(16);
        printf("\npp er = %u stor",pp);
        pp=adc10bit(0);
        lcd_pos(0);
        lcd("Integer =");
        lcd(ord(pp));
        lcd_pos(16);
        lcd("Spænding=");
        lcd(ord(volt(pp)));
        printf("\n%s",ord(volt(pp)));
        for(tael=0;tael<MAX;tael++)
        {
        tabel[tael]=0xff;
        pp=tabel[tael];
        if(pp!=tabel[tael]) printf(" fejl ved addr=%s",ord(tael));
        tabel[tael]=0x00;
        pp=tabel[tael];
        if(pp!=tabel[tael]) printf(" fejl ved addr=%s",ord(tael));
        }
        delay(30);
      ok();
  }// end "while(!stopbit)"
}


// ########################################################
// --------------------------------------------------------
//      lcd_pos(0);
//      lcd(" Æ Ø Å æ ø å 0");
//      LCD 
// --------------------------------------------------------
void lcd(unsigned char *s)
{
// s indeholder abs addr, p benyttes som addr counter
unsigned char *p=s;
while(*p != '\0') //mendens indholdet *p peger på, ikke er '\0'
{
  switch(*p)
  {
    case 'Æ': lcd_data(0);break;
    case 'Ø': lcd_data(1);break;
    case 'Å': lcd_data(2);break;
    case 'æ': lcd_data(3);break;
    case 'ø': lcd_data(4);break;
    case 'å': lcd_data(5);break;
    default : lcd_data(*p);break;
  }// end switch
  p++;
}  // end while
}
// --------------------------------------------------------
//              LCD 
// Dansk tegn sæt Æ,Ø,Å,æ,ø,å OK 21 AUG 1998 Dan Nielsen
// --------------------------------------------------------
void lcd_dansk(void)
{
unsigned char dum;
//const unsigned char dansk[]=
//  {
//  0x1f,0x14,0x14,0x1f,0x14,0x14,0x17,0x00, // Æ
//  0x01,0x0e,0x13,0x15,0x19,0x0e,0x10,0x00, // Ø
//  0x04,0x0a,0x0e,0x11,0x1f,0x11,0x11,0x00, // Å
//  0x00,0x00,0x1e,0x05,0x1f,0x14,0x0f,0x00, // æ
//  0x00,0x00,0x01,0x0e,0x0a,0x0e,0x10,0x00, // ø
//  0x04,0x0a,0x0e,0x01,0x0f,0x11,0x0f,0x00  // å
//  };
  lcd_command(0x40);
  for(dum=0;dum<8*6;lcd_data(dansk[dum]),dum++);
}

// --------------------------------------------------------
//              LCD  Row=2, collum == "DISPLAY"
// Row 0 = 00..DISPLAY-1        if DISPLAY==40 then 00..39
// Row 1 = DISPLAY..(DISPLAY*2)-1                    40..79
// --------------------------------------------------------
void lcd_pos(unsigned char pos)
{
unsigned char dummy;
  dummy=64-DISPLAY;
  lcd_busy();            // vent til LCD Display er klar
  if(pos>=DISPLAY)
    {
    pos=pos+dummy;
    }
  lcd_command(pos+0x80); //
}

// --------------------------------------------------------
//              LCD 
// --------------------------------------------------------
void lcd_command(unsigned char inp)
{
  lcd_busy();          // vent til LCD Display er klar
  LCD_RS=FALSE;        // True=Data input, False=Command input
  LCD_RW=FALSE;        // True=Read, False=Write
  LCD_E=TRUE;          // Enabel LCD Display
  LCDPORT=inp;        // skriv til port 4
  delay(1);            // vent lidt
  LCD_E=FALSE;        // Enabel LCD Display
}
// --------------------------------------------------------
// --------------------------------------------------------
void lcd_data(unsigned char inp)
{
  lcd_busy();          // vent til LCD Display er klar
  LCD_RS=TRUE;        // True=Data input, False=Command input
  LCD_RW=FALSE;        // True=Read, False=Write
  LCD_E=TRUE;          // Enabel LCD Display
  LCDPORT=inp;        // skriv til port 4
  delay(1);            // vent lidt
  LCD_E=FALSE;        // Enabel LCD Display
  LCD_RS=FALSE;        // True=Data input, False=Command input
}

// --------------------------------------------------------
//              LCD Functioner
// --------------------------------------------------------
void lcd_init(void)
{
unsigned char  dummy;
  dummy = LCDPORT ;    // P4 input
  dummy = 0x38;        // Function Set value

  delay(100);          // Power on wait
  lcd_command(dummy);  // System Function    1
  delay(100);          // Power on wait
  lcd_command(dummy);  // System Function    2
  delay(100);          // Power on wait
  lcd_command(dummy);  // System Function    3
  delay(100);          // Power on wait
  lcd_command(dummy);  // system Function set 4 gange ialt
  delay(5);
  lcd_command(0x0c);  // Display ON/OFF Control
  delay(5);
  lcd_command(0x06);  // Entry Mode Set
  delay(5);
  lcd_command(0x18);  // Cursor or Display Shift
  delay(5);
  lcd_command(0x02);  // home
  delay(5);
  lcd_command(0x01);  // Clear
  delay(5);
  lcd_dansk();        // Dansk tegn sæt ÆÅØæøå 0..5

  LCD_E=FALSE;        // Enabel LCD Display
  LCD_RS=FALSE;        // True=Data input, False=Command input
  LCD_RW=FALSE;        // True=Read, False=Write
  dummy = LCDPORT ;    // P4 input
}


// --------------------------------------------------------
//    LCD_busy , OK,  Testet 21 AUG 1998 Dan Nielsen
//    bliver hængende i rutine indtil display er klar
// --------------------------------------------------------
void lcd_busy(void)
{
unsigned char  dummy;
  dummy=LCDPORT;      // P4 input
  LCD_RW=TRUE;        //
  LCD_RS=FALSE;      //
  LCD_E=TRUE;        // set kontrol pins
  while(LCDPORT.7);  // vent intil P4.7 low
  LCD_E=FALSE;        // reset kontrol pins
  LCD_RS=FALSE;      //
  LCD_RW=FALSE;      //
  dummy=LCDPORT;      // P4 input
  return();
}

// --------------------------------------------------------
//    ord() , OK,  Testet 21 AUG 1998 Dan Nielsen
//    returnere addressen på en string der indeholder værdien af int
// --------------------------------------------------------
unsigned char* ord(unsigned int x)
{
xdata unsigned char s[5];  // text string
unsigned int y; 
  // find antal 10000 og læg antal i første position i string
  if      (x >=    0 && x <=  9999) { y=x-    0; s[0]='0'; }
  else if (x >= 10000 && x <= 19999) { y=x-10000; s[0]='1'; }
  else if (x >= 20000 && x <= 29999) { y=x-20000; s[0]='2'; }
  else if (x >= 30000 && x <= 39999) { y=x-30000; s[0]='3'; }
  else if (x >= 40000 && x <= 49999) { y=x-40000; s[0]='4'; }
  else if (x >= 50000 && x <= 59999) { y=x-50000; s[0]='5'; }
  else if (x >= 60000 && x <= 65535) { y=x-60000; s[0]='6'; }
  else                              { y=0;      s[0]='0'; }
  x=y;
  //nu er talet under 10000

  // find antal 1000 og læg antal i anden position i string
  if      (x >=    0 && x <=  999) { y=x-    0; s[1]='0'; }
  else if (x >=  1000 && x <=  1999) { y=x- 1000; s[1]='1'; }
  else if (x >=  2000 && x <=  2999) { y=x- 2000; s[1]='2'; }
  else if (x >=  3000 && x <=  3999) { y=x- 3000; s[1]='3'; }
  else if (x >=  4000 && x <=  4999) { y=x- 4000; s[1]='4'; }
  else if (x >=  5000 && x <=  5999) { y=x- 5000; s[1]='5'; }
  else if (x >=  6000 && x <=  6999) { y=x- 6000; s[1]='6'; }
  else if (x >=  7000 && x <=  7999) { y=x- 7000; s[1]='7'; }
  else if (x >=  8000 && x <=  8999) { y=x- 8000; s[1]='8'; }
  else if (x >=  9000 && x <=  9999) { y=x- 9000; s[1]='9'; }
  else                              { y=0;      s[1]='0'; }
  x=y;
  //nu er talet under 1000

  // find antal 100 og læg antal i tredie position i string
  if      (x >=    0 && x <=    99) { y=x-    0; s[2]='0'; }
  else if (x >=  100 && x <=  199) { y=x-  100; s[2]='1'; }
  else if (x >=  200 && x <=  299) { y=x-  200; s[2]='2'; }
  else if (x >=  300 && x <=  399) { y=x-  300; s[2]='3'; }
  else if (x >=  400 && x <=  499) { y=x-  400; s[2]='4'; }
  else if (x >=  500 && x <=  599) { y=x-  500; s[2]='5'; }
  else if (x >=  600 && x <=  699) { y=x-  600; s[2]='6'; }
  else if (x >=  700 && x <=  799) { y=x-  700; s[2]='7'; }
  else if (x >=  800 && x <=  899) { y=x-  800; s[2]='8'; }
  else if (x >=  900 && x <=  999) { y=x-  900; s[2]='9'; }
  else                              { y=0;      s[2]='0'; }
  x=y;
  //nu er talet under 100

  // find antal 10 og læg antal i fjerde position i string
  if      (x >=    0 && x <=    9) { y=x-    0; s[3]='0'; }
  else if (x >=    10 && x <=    19) { y=x-  10; s[3]='1'; }
  else if (x >=    20 && x <=    29) { y=x-  20; s[3]='2'; }
  else if (x >=    30 && x <=    39) { y=x-  30; s[3]='3'; }
  else if (x >=    40 && x <=    49) { y=x-  40; s[3]='4'; }
  else if (x >=    50 && x <=    59) { y=x-  50; s[3]='5'; }
  else if (x >=    60 && x <=    69) { y=x-  60; s[3]='6'; }
  else if (x >=    70 && x <=    79) { y=x-  70; s[3]='7'; }
  else if (x >=    80 && x <=    89) { y=x-  80; s[3]='8'; }
  else if (x >=    90 && x <=    99) { y=x-  90; s[3]='9'; }
  else                              { y=0;      s[3]='0'; }
  x=y;
  //nu er talet under 10

  // find rest og læg i femte position i string
  if      (x == 0)  s[4]='0';
  else if (x == 1)  s[4]='1';
  else if (x == 2)  s[4]='2';
  else if (x == 3)  s[4]='3';
  else if (x == 4)  s[4]='4';
  else if (x == 5)  s[4]='5';
  else if (x == 6)  s[4]='6';
  else if (x == 7)  s[4]='7';
  else if (x == 8)  s[4]='8';
  else if (x == 9)  s[4]='9';
  else              s[4]='0';

  s[5]='\0';  // Afslut string men NULL i sjete position
              // printf("\n%s",&s);
return(&s);    // Returnere adresse værdien på string
}


// --------------------------------------------------------
//  Timer 0 interrupt, optages til delay function
// --------------------------------------------------------
void inctimer () interrupt TIMER0
{
  // This interrupt will come every 200 micro second
  // and update the delayfrac variable every 1/1000 second
  if (frac++ >= 5)  //benyt 3905 for 1 sek delay function
  {
  delayfrac++;
  frac = 0;
  }
}

// --------------------------------------------------------
// ******** Delay i milli sekunder *********************
// tjekket 21 AUG 1998 af Dan Nielsen, Køre ok
// --------------------------------------------------------
void delay(unsigned int ms) // Delay i msek           
{
  delayfrac = 1;            //
  while(ms >= delayfrac);  // Gennem løbes mindst en gang
}


// --------------------------------------------------------
// --------------------------------------------------------
void init(void)
{
  stopbit=FALSE;
  Inte_rupt_init();      //  interrupt initialisering
  serial_init_9600();    //    Seriel initialicering
//  serial_init_19200(); //    Seriel initialicering
//  serial_init_57600(); //    Seriel initialicering
}

// --------------------------------------------------------
// ********************** ok *************************
// Skal ikke bruges i den endelige code. Kun til test 
// --------------------------------------------------------
void ok(void)    // hjælpe test af programmering   
{                // tænder og slukker LYSDIODE p5.6
  LED=!LED;      // Inverterer Lysdiode }
}

// --------------------------------------------------------
//  *********** Seriel Port *** 9600 baud **************
//  Denne procedure skal kun bruges når seriel port skal
//  sættes op. Her er sat til 1start, 1stop, 8 data bit 
//  Med et 11,059MHz XTal monteret, timer 1 benyttes som
//  baudrate generator i mode 2 8-bit auto reload.   
//  denne funktion er ok DMN JAN-1998.       
// --------------------------------------------------------
void serial_init_9600(void) //  Seriel initialicering
{                      // 1-start, 8-data, 1-stop,   
  unsigned char dummy; // no-parity, async.
  SCON  = 0x7C;      // Seriel mode 1: 8-bit UART 
  ADCON &= 0x7F;      // Baud Rate Disable, BD=FALSE
  PCON  &= 0x7F;      // $7F = "SMOD" sat FALSE     
  TMOD  |= 0x20;      // timer1 mode2 8bit autoreload
  TH1    = 0xFD;      // BaudRate 1200=E8,2400=F4,4800=FA,9600=FD
  ET1    = FALSE;      // Timer 1 intr Disable       
  TR1    = TRUE;      // turn timer/counter 1, on   
  TI    = TRUE;      // tømmer TX buffer ???       
  dummy  = SBUF;      // tømmer RX buffer ???
  RI    = FALSE;      // Klar til at modtage       
}

// --------------------------------------------------------
//  *********** Seriel Port *** 19200 baud **************
//  Denne procedure skal kun bruges når seriel port skal
//  sættes op. Her er sat til 1start, 1stop, 8 data bit 
//  Med et 11,059MHz XTal monteret, timer 1 benyttes som
//  baudrate generator i mode 2 8-bit auto reload.   
//  denne funktion er ok DMN JAN-1998.       
// --------------------------------------------------------
void serial_init_19200(void) //  Seriel initialicering
{                    //          1-start, 8-data, 1-stop,   
  unsigned char dummy; //          no-parity, async.
  SCON  = 0x7C;      // Seriel mode 1: 8-bit UART 
  ADCON &= 0x7F;      // Baud Rate Disable, BD=FALSE
  PCON  |= 0x80;      // $80 = "SMOD" sat TRUE     
  TMOD  |= 0x20;      // timer1 mode2 8bit autoreload
  TH1    = 0xFD;      // BaudRate 19200=0xFD
  ET1    = FALSE;      // Timer 1 intr Disable       
  TR1    = TRUE;      // turn timer/counter 1, on   
  TI    = TRUE;      // tømmer TX buffer ???       
  dummy  = SBUF;      // tømmer RX buffer ???
  RI    = FALSE;      // Klar til at modtage       
}


// --------------------------------------------------------
//  *********** Seriel Port *** 57600 baud **************
//  Denne procedure skal kun bruges når seriel port skal
//  sættes op. Her er sat til 1start, 1stop, 8 data bit 
//  Med et 11,059MHz XTal monteret, timer 1 benyttes som
//  baudrate generator i mode 2 8-bit auto reload.   
//  denne funktion er ok DMN AUG-1998.       
// --------------------------------------------------------
void serial_init_57600(void) //  Seriel initialicering
{                    //          1-start, 8-data, 1-stop,   
  unsigned char dummy; //          no-parity, async.
  SCON  = 0x7C;      // Seriel mode 1: 8-bit UART 
  ADCON &= 0x7F;      // Baud Rate Disable, BD=FALSE
  PCON  |= 0x80;      // $80 = "SMOD" sat TRUE     
  TMOD  |= 0x20;      // timer1 mode2 8bit autoreload
  TH1    = 0xFF;      // BaudRate 57600=0xFF
  ET1    = FALSE;      // Timer 1 intr Disable       
  TR1    = TRUE;      // turn timer/counter 1, on   
  TI    = TRUE;      // tømmer TX buffer ???       
  dummy  = SBUF;      // tømmer RX buffer ???
  RI    = FALSE;      // Klar til at modtage       
}

// --------------------------------------------------------
//          Modtag en Byte fra seriel port
// --------------------------------------------------------
unsigned char rexbyte(void) //  Seriel initialicering
{
  while(!RI);        // vent på modtager klar     
  RI=FALSE;          // gør klar til at modtag igen
  return(SBUF);      // læg modtaget byte i RX_Byte
}

// --------------------------------------------------------
//    Sender en Byte ad gangen Feks. txbyte(13) = Line Feed
// --------------------------------------------------------
void txbyte(unsigned char send)
{         
  while(!TI);        //    vent til txd er klar
  SBUF = send;      //    læg i tx buffer     
  TI  = FALSE;      //    send indhold af TX buffer
}         
// --------------------------------------------------------
//          Sender line Feed and Return
// --------------------------------------------------------
void newline(void)
{
  txbyte(13);      //    line feed               
  txbyte(10);      //    return                             
}
// --------------------------------------------------------
// --------------------------------------------------------


// --------------------------------------------------------
//  ************** A/D CONVERTER 8 Bit *******************
//  Denne Function returnere en Byte, der representere Målt
//  Spænding på AD-Port(X). 0= 0 mV,  255= +5000 mVolt 
//  Eks: Volt=adc8bit(2); måler fra port"AN2".           
//  Ved 2.5Volt på AD-Port 2, vil retur værdi blive 127; 
// --------------------------------------------------------
unsigned char adc8bit (unsigned char portnr)
{       
  ADM    = FALSE;        //  ADM '0' en conversion         
  ADCON |= portnr;      //  Mål på portnr "portnr"     
  DAPR  = 0x00;        //  trig ved at skrive til DAPR
  while(BSY);            //  Vent til måling er færdig 
  return(ADDAT);        //  Hent resultat i "ADDAT"   
}

// --------------------------------------------------------
//  ************** A/D CONVERTER  10 Bit *****************
//  Denne Function returnere en Integer, der representere Målt
//  Spænding på AD-Port(X). 0= 0 mV,  1023= +5000 mVolt 
//  Eks: Volt=adc10bit(2); måler fra port "AN2".         
//  Ved 2.5Volt på AD-Port 2, vil retur værdi blive 512; 
// --------------------------------------------------------
int adc10bit(unsigned char portnr)
{
  unsigned char dum,measure;
  int offset;
//const unsigned char range[]={0x00,0x40,0x62,0x84,0xA6,0xC8,0xEA,0x0C};
//                    range[    0  , 1  , 2  , 3  , 4  , 5  , 6  , 7  ]
//            max min  hex 
//  range[0]=%0000 0000; 0x00  Fra 5.000 til 0.000 Volt
//  range[1]=%0100 0000; 0x40  Fra 1.250 til 0.000 Volt
//  range[2]=%0110 0010; 0x62  Fra 1.875 til 0.625 Volt
//  range[3]=%1000 0100; 0x84  Fra 2.500 til 1.250 Volt
//  range[4]=%1010 0110; 0xA6  Fra 3.125 til 1.875 Volt
//  range[5]=%1100 1000; 0xC8  Fra 3.750 til 2.500 Volt
//  range[6]=%1110 1010; 0xEA  Fra 4.375 til 3.125 Volt
//  range[7]=%0000 1100; 0x0C  Fra 5.000 til 3.750 Volt

  ADM    = FALSE;        //  ADM '0' one conversion         
  ADCON |= portnr;      //  Mål på portnr "portnr"     
  DAPR  = range[0];    //  trig ved at skrive til DAPR
  while(BSY);            //  Vent til måling er færdig 
  measure=ADDAT;        //  Hent resultat i "ADDAT"   
  //    i hvilket område ligger spændingen ??
  if ( (00  <= measure) && (measure <= 48 ) ) { dum=1; offset=  0; }
  if ( (49  <= measure) && (measure <= 80 ) ) { dum=2; offset=128; }
  if ( (81  <= measure) && (measure <= 112) ) { dum=3; offset=256; }
  if ( (113 <= measure) && (measure <= 144) ) { dum=4; offset=384; }
  if ( (145 <= measure) && (measure <= 176) ) { dum=5; offset=512; }
  if ( (177 <= measure) && (measure <= 208) ) { dum=6; offset=640; }
  if ( (209 <= measure) && (measure <= 255) ) { dum=7; offset=768; }
             
//  Skift til nærmeste spændings område og mål igen
  DAPR  = range[dum];  //  trig ved at skrive til DAPR
  while(BSY);            //  Vent til måling er færdig 
  measure=ADDAT;        //  Hent resultat i "ADDAT"   
           
//  læg målt spænding sammen med start af område   
  offset += measure;    // type convertering
  return(offset);
}             


// --------------------------------------------------------
//  Volt beregning
// --------------------------------------------------------
unsigned int volt(unsigned int vaerdi)
{
unsigned int tal,temp;
  temp= vaerdi * 50;
  tal=temp / 10.23;
return  (tal);
}
// --------------------------------------------------------
// --------------------------------------------------------

// ******************** INTERUPT *************************
// Initialisering af interrupt rutiner, her skal kun tændes
// for de interrupt's, som man ønsker at bruge. Se manual 
// Jeg har valgt at aktivere alle interrupt,  EAL:=TRUE   
// Derefter skal de individuelle interrupt's settes.     
// Dette er afhængig af de hvad man skal bruge.           
// Efter hardware Reset, Resettes alle interrupt registre 
// --------------------------------------------------------
void Inte_rupt_init(void)
{
  TMOD |= 0x02;  // Timer1 M1 true: 8 bit autoreload timer */
  EX0  =TRUE;    // Ext int_0 Enable  p3.2     
  IT0  =TRUE;    // Bagkant trig af int0 signal
  EX1  =TRUE;    // Ext int1 Enable  p3.3     
  IT1  =TRUE;    // Bagkant trig af int1 signal
  ES  =FALSE;    // Seriel channel intr Disable
  TR0  =TRUE;
  ET0  =TRUE;    // Timer 0 intr Enable       
  TH0  =72;      // interrupt every 200 microsecond (if 11MHz clock)
  ET1  =FALSE;    // Timer 1 intr Disable       
  ET2  =FALSE;    // Timer 2 intr Disable       
  EADC =FALSE;    // A/D Converter intr Disable 
  EX2  =FALSE;    // Ext int2 Disable  p1.4     
  EX3  =FALSE;    // Ext int3 Disable  p1.0     
  EX4  =FALSE;    // Ext int4 Disable  p1.1     
  EX5  =FALSE;    // Ext int5 Disable  p1.2     
  EX6  =FALSE;    // Ext int6 Disable  p1.3     
  EXEN2=FALSE;    // Timer 2 Ext reload Disable 
  P3.2 =TRUE;    // Interrupt.0 Reset p3.2     
  P3.3 =TRUE;    // Interrupt.1 Reset p3.3     
  int_0=FALSE;    // Reset boolean           
  int_1=FALSE;    // Reset boolean           
  EAL  =TRUE;    // Enable All interrupt's     
}

// --------------------------------------------------------
// Dette exekveres når INT0 aktiveres, der sætttes et
// flag (int_0), som skal resette manuelt efter brug. 
// --------------------------------------------------------
void inter0 ( ) interrupt INT0
{
//  printf("\n Interrupt '0' er er blevet aktiveret");
  int_0=TRUE;  //  extern int0 port3.2
}

// --------------------------------------------------------
// Dette exekveres når INT1 aktiveres, der sætttes et
// flag (int_0), som skal resette manuelt efter brug. 
// --------------------------------------------------------
void inter1 ( ) interrupt INT1
{
  int_1=TRUE;  //  extern int1 port3.3
}


// --------------------------------------------------------
// Denne procedure ser om der er kommet interrupt's, polling teknik   
// --------------------------------------------------------
void polling_int(void)// Hvis Int0 er blevet aktiveret, udføres denne code. 
{                    // HusKat resette alle interrupt's
 
//  Hvis INT0 er blevet aktiveret, udføres denne code. 
    if (int_0)
    {
    printf("\n Interrupt '0' er er blevet aktiveret, Hej med dig ");
    int_0=FALSE;  //            reset boolean         
    }

//  Hvis INT1 er blevet aktiveret, udføres denne code. 
    if (int_1)
    {
    printf("\n Interrupt '1' er er blevet aktiveret Hej Dan");
    int_1=FALSE;  //            reset boolean         
    }
}


// --------------------------------------------------------
//  ***************************************************
//  ***** Her starter den hardware afhængige code *****
//  ***************************************************
// --------------------------------------------------------
// --------------------------------------------------------

// ############## Ending ##################################
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester