Stap 6: De Software
Zoals met alle C-programma's we eerst hebben omvat out. U moet io.h en interrupt.h voor dit project. Vervolgens wordt gedefinieerd ik sommige symbolen zodat zou het gemakkelijker om te werken met hen in het programma. Ik denk dat het gemakkelijker is om te weten wat ik doe wanneer ik gebruik SPI_PORT in plaats van PORTB. Dan hebben we de functie prototypes; niets te speciaal hier. Tot slot in dit gedeelte hebben we onze globale variabele definities. Er zijn een paar die ik zou graag om uw aandacht te brengen.
int currentRow = 0;
unsigned int kraai = 0, cCol = 0;
int rowRead, colRead, factor;
int soft_prescaler = 0;
niet-ondertekende lang tekening [8] = {0};
De currentRow-variabele, bevat zoals de naam al doet vermoeden, de waarde van de huidige rij die we bekijken. U ziet precies wat dit wordt gebruikt voor een beetje later. Kraai en cCol houden de waarden van de rij en kolom van de cursor. rowRead en colRead houden de waarden van de ADC lezen ontleend aan de potten. Deze zal worden gebruikt bij de berekening van de waarde van de variabelen van de kraai en cCol. De soft_prescaler wordt gebruikt om verder te verdelen de klok met de software; het zullen we later bespreken. Tenslotte is de belangrijkste variabele een array van niet-ondertekende lange ints tekening genoemd. U zult opmerken dat deze array bevat acht elementen-één voor elke rij. Dit houdt de 32-bits waarmee de LEDs voor elke kolom.
Nu laten we overgaan tot sommige functies. We beginnen met de belangrijkste functie. Na het uitvoeren van de set van de Timer, SPI, en de inputs en outputs betreden we de belangrijkste programma lus. Het eerste dat binnen deze lus is een indien verklaring.
als (teller < cycli)
{
rowReadings [teller] = Analog_Read(PC4);
colReadings [teller] = Analog_Read(PC5);
teller ++;
}
Dit is gewoon het nemen van een steekproef van ADC lezingen over zoveel cycli. Dit wordt gebruikt voor het berekenen van een gemiddelde van de ADC lezen en voorkomt problemen met de tekening. Invoeren van het anders zal laten zien hoe dit wordt gedaan.
anders
{
Gemiddelde van alle rij- en Col ADC lezingen
colRead = CycAvg(colReadings);
rowRead = CycAvg(rowReadings);
Counter = 0;
Nadat we een steekproef van ADC waarden voor de rij- en we kunnen ze met behulp van de CycAvg functie gemiddelde hebben. Dit is gewoon een generieke gemiddeld functie die vat de waarden en vervolgens worden gedeeld door het totale aantal waarden. Ik ga niet om erover te praten hier als je het in de code vinden kunt. Nou, moeten nu hebben we de ADC-lezingen die we van de potten willen, we dit omzetten in een rij en kolom nummer zodat we de cursor er kunt plaatsen. Dit wordt vervolgens verwerkt.
als (colRead / DELER ! = cCol & & colRead / DELER < dimensie)
{
cCol = colRead / DELER;
}
De waarde van de column cursor is ongecompliceerd om te berekenen. We controleren dat de nieuwe waarde niet hetzelfde als de oude waarde is (omdat zou er geen behoefte aan het herberekenen) en wij ervoor zorgen dat de cursor niet verder dan onze 16 x 16 tekening oppervlak. We wijs de waarde van de ADC lezen gedeeld door de waarde van DELER. DELER is gewoon de maximumwaarde van de ADC gedeeld door de afmetingen van het beeldscherm (1024/16 = 64, zodat elke 64 zijn we op een andere rij of kolom). De waarde van de rij cursor is een beetje ingewikkelder.
als (rowRead / DELER ! = kraai & & rowRead / DELER < dimensie)
{
als (rowRead / DELER > = 8)
{
cRow = rowRead / DELER - 8;
factor = 0;
}
anders
{
cRow = rowRead / DELER;
factor = 16;
}
}
Dus wat er met deze extra als verklaring? Dit gaat terug op hoe wij de beeldschermen aangesloten alsof het eigenlijk een 8 x 32 display in plaats van een 16 x 16. De eerste 16 bits van onze tekening variabele komen overeen met de eerste 16 kolommen van het 8 x 32 display. De overige 16 bits komen overeen met de tweede 16 kolommen. Wanneer we het display 16 x 16 zijn we de laatste 16 kolommen verplaatsen en brengen ze onder de firs 16 kolommen 8 meer rijen kunstmatig te scheppen. Als we berekenen van de rij van de cursor op dezelfde manier willen zoals wij de cursor kolom deden kunnen we eindigen met een waarde van meer dan 8. Onthoud, dat wij hebben slechts acht rijen aangezien onze display technisch 8 x 32, is zodat dit leidt een probleem tot. Dus als het resultaat van de onderverdeling van de ADC door een DELER groter dan 8 is, die we moeten aftrekken 8 en gebruik dat als de rij, kunnen anders we gewoon nemen het resultaat betreft. We moeten ook bijhouden van al dan niet de tekening in de eerste 16 kolommen (rijen 9-16) of de laatste 16 kolommen (rijen 1-8 gebeurt). Dat is waar de variabele factor in komt. Dit moet meer zinvol wanneer we eigenlijk een waarde aan de tekening variabele vervolgens toewijst.
tekening [kraai] | = (0x80000000 >> (cCol + factor));
Nogal wat hier gebeurt. Eerst geven we de matrix van onze cursor kolom als een index en vervolgens zullen we bitniveau of deze met het volgende deel. We gebruiken bitniveau of hier omdat we houden van alle bits die al ingesteld willen, waar ze zijn en alleen ingesteld het een overeenkomstige op de cursorlocatie. Aan de rechterkant van de exploitant, zijn we een enkele bit verschuiven naar de juiste locatie. Bijvoorbeeld, stel dat de waarde van cCol is 4 en kraai is 5. In dit scenario, tekening [5] | = (0x80000000 >> (4 + 16)) = 0b0000000000000000|0001000000000000. Om beter te verduidelijken welke bits komen overeen met wat de 16 meest significante bits overeenkomen met de kolommen van de rijen 1-8, corresponderen de minst significante bits van 16 met rijen 9-16.
Het laatste deel van deze lus wordt gecontroleerd als zowel overhelt schakelaars zijn gesloten op hetzelfde moment. Het is zeer eenvoudig en is afhankelijk van het feit dat er een grote kans dat de twee schakelaars zal sluiten op hetzelfde moment wanneer het apparaat wordt geschud.
Schakel scherm als tilt sensoren zijn struikelde.
als (bit_is_clear(PINC,0) & & bit_is_clear (PINC, 1))
{
clrscr();
}
Nu de tekening gebeurt moeten we om het te krijgen aan de weergave. Dit wordt verzorgd door de Interrupt Service Routine (ISR) die op elke overloop timer wordt geactiveerd. Laten we eens kijken.
ISR (TIMER0_OVF_vect)
{
soft_prescaler ++;
als (soft_prescaler == SFT_PRESCAL_MAX)
{
currentRow = (currentRow + 1) % 8;
Doorgeven van gegevens over SPI
SPI_Transmit(Drawing[currentRow]);
PORTD = (1 << currentRow);
soft_prescaler = 0;
}
}
Het eerste wat dat we doen in de ISR is de zachte prescaler verhogen. De zachte prescaler in principe stelt ons in staat zorg de tijd elke rij is iets anders dan wat we met de de ATmega hardware prescaler kunnen weergegeven. Als je kijkt naar de functie van Timer_Init() ziet u prescale we de klok van 8 met de hardware. Zo wordt onze 16 MHz klok 2MHz. Met een zachte prescaler met een maximale waarde van 15 die we de tijd brengen kunnen wordt elke rij weergegeven tot ongeveer 133 kHz. Dit zou niet mogelijk zijn met een prescaler van hardware. Anyway, laten we overgaan.
Wanneer we er in slagen de zachte prescaler max die wij eerst besluiten welke rij wilt we weergeven. Elke keer dat de branden van de interrupt slechts één rij wordt weergegeven. Dit gebeurt zo snel dat onze ogen de wijzigingen niet zien en zo het beeld ziet er solide. Deze techniek heet multiplexing en het voor veel en veel toepassingen gebruikt. Instellen van de huidige rij we zullen eerst een toe te voegen uit te breiden van de rij vervolgens mod door 8 zodat de waarde zal altijd ergens tussen 0-7. Dan sturen we de tekening voor de huidige rij naar de SPI_transmitt-functie voor het verzenden van de gegevens aan de 595s. Na dat we één van de Port D pinnen hoge overeenkomt met de huidige rij instellen. Recall die deze pinnen zijn aangesloten op de ULN2803s. Tot slot, wij opnieuw de zachte prescaler nul te verrichten helemaal tegenover weer.
That's pretty much it. Alle andere functies zijn alleen de ondersteuning van deze twee. Zeker check ze uit in de bijgevoegde code.