Fórum témák
- • Felajánlás, azaz ingyen elvihető
- • Graetz-híd
- • Klíma szervizelés, javítás
- • Elfogadnám, ha ingyen elvihető
- • Villanyszerelés
- • Erősítő mindig és mindig
- • Indukciós főzőlap,sütő bekötése, kábelek kiépítése
- • 3D nyomtatás
- • Érdekességek
- • Vicces - mókás történetek
- • V-FET és SIT erősítő kapcsolások
- • HiFi javítás
- • Peltier cella
- • Kazettás magnó (deck) javítása
- • Házi vízmű
- • Aszinkron motorok tekercselése
- • Kompresszor építés
- • Alternativ HE találkozó(k)
- • Hőlégfúvó
- • Forrasztási 1×1 forrasztástechnikai miértek
- • Mosogatógép hiba
- • Mikrohullámú sütő javítás, magnetron csere, stb.
- • Okosóra
- • SMD, mi a típusa?
- • Hűtőgép probléma
- • Rádióamatőrök topikja
- • Robotfűnyíró vagy fűnyíró robot
- • Fényerőszabályzók váltókapcsolásban
- • Kugoo Kirin S1 Pro teljes alkatrészcsere után sem indul
- • Klíma beszerelése, fűtés-hűtés házilag
- • Quad 405-ös erősítő tapasztalatok és hibák
- • Kondenzátor
- • Kávéfőzőgép hiba
- • Fluoreszcens kijelzők (VFD) használata
- • Forrasztópákák - melyik miért jó
- • Feszültség teszter és jelző
- • Fejhallgató erősítő
- • Arduino
- • RIAA korrektor
- • Mosógép vezérlők és általános problémáik
- • LED szalag
- • STK erősítők javítások
- • Autórádió (fejegység) problémák, kérdések, válaszok
- • Számítógép hiba, de mi a probléma?
- • Frekvenciaváltó 1-ről 3 fázisra
- • Vásárlás, hol kapható?
- • Villanymotor bekötése
- • 555-ös IC-s kapcsolások
- • Autóriasztó és központi zár
- • Központi zár
- • Napelem alkalmazása a lakás energia ellátásában
- • Robotika kezdőknek
- • Rendelés külföldről (eBay - Paypal)
- • Tervezzünk nyákot EasyEDA-val
- • Triak működése
» Több friss téma
|
Szia!
Még dolgozok rajta, nincs kész, de már vannak fejlemények. Sajnos nem tudtam foglalkozni vele az elmúlt napokban, de ma már haladtam is vele. Még a fő logika hiányzik, minden egyéb kész. Megpróbálom darabokra szedni a logikát is, hogy minél könnyebben átlátható legyen az is. Pár függvényt már kiszerveztem .c és .h fájlokba is, mint például a timer1, PWM, és a PIN_setup-ot is. Ezek jól működnek, így a fő programban csak meg kell hívni őket 1x, ezáltal a fő program sokkal átláthatóbb lesz szerintem.
Jelentkezem mihamarabb, és bocs a késlekedésért!
Üdv!
Gépkocsimba szeretnék belső világítás vezérlést kreálni.
Az eredei kódot nem én írtam, itt az oldalon találtam egy hasonlót amit mintaként szerettem volna némi átalakítással felhasználni.
Az eredetit potyo készítette 2008-ban. Itt a linkben megtalálod. A 3. oldalon leírja miért ilyen a kód, az 5. oldalon fent van a hex. és c. is.
Ő úgy oldotta meg, hogy nem használ interruptot.
Én csak egy táki-máki ember vagyok, aki "talán" sejti hogy hogyan is kell ilyet csinálni.
Azért csak a kód első részletét raktam fel, mert a delay és a pwm is benne van.
A pwm megy, a számláló viszont sem timer2 vel, sem timer1-el nem működik.
Idézet: „
Ez miért ilyen?
#define HA_IDO ((HALV_IDO/255)*255-1) ”
Nem tudom miért ilyen, de ez működik.
Nem tudom, hogy ennek pl működnie kellene, de ez sem működik és nem értem miért:
if (bv_ajto == 0) // ha kinyílt az ajtó
{
PORTC.RC5 = 1; // bekapcsol a led
szamlalo= 3000; // késleltet
PORTC.RC5 = 0; // kikapcsol
}
Idézet: „
De a témafelvető nem reagál, már kezdtem azt hinni lesz egy kis programozási feladat. ”
Ha gondolod leírom miről is szólna ez az egész, de gondoltam kilogikázom én, bár jelenleg úgy látszik túlnő rajtam
Én azt hittem, hogy timer2-nek nincs átfordulásra interrupt.
TMR2IF: Timer2 to PR2 Match Interrupt Flag bit
1 = Timer2 to PR2 match occurred (must be cleared in software)
0 = Timer2 to PR2 match has not occurred
A Timer2-nek van overflow interruptja? Nem csak egyezésre? Az adatlapot nem néztem olyan mélyen át, nekem úgy tűnt, hogy ennél a típusnál nincs a timer2-nek, a timer1-nek és a timer0-nak van. Ezért írtam hogy más, mint amivel találkoztam eddig. A PR2-vel való egyezésre ad interuptot, ha jól értem. (most lehet keverem, mert épp Arduino timer1 ComparA, ComparB, és overflow interrupt van a fejemben)
A kódot felületesen olvasva egyik interrupt sincs engedélyezve, nincs erre függvény felhúzva, ebben az esetben lesz egyezés? Mikor?
Idézet: „
2. #define HA_IDO ((HALV_IDO/255)*255-1) kérdése.
A műveleteket a fordítók a saját alapbeállításuk szerinti típussal végzik, mivel nincs megadva a változók típusa. A Hi-Tech C 32 bites egész típussal számol. Az osztás is egyész osztás. Így a sor egy kerekítési művelet. ”
Ezt nem tudtam, köszi!
De épp az ilyenek adják az okát, hogy ki legyen szervezve minden és tesztelve legyen rendesen minden, akár csak egy blink-kóddal is, amivel a timer-t ellenőrizni lehet könnyedén.
Megnézem milyen van nekem itthon, azt tudom, hogy 16F, de nem tuti, hogy 648-as. A hozzászólás módosítva: Jún 9, 2024
Ez a kód nekem nem tetszik.
Most fejből írom mindezt, lehet másképp van. Nem használ interrupot, kikapcsolja mind a Timer2 mind a globális interruptot. Akkor hogy lesz az interrupt flag 1, amire hivatkozik a for(; ![](/pic/smile/wink.gif) után rögtön?
A for helyett is lehetne While();
PIE1=0; Egy egész regiszter értéke nulla. Ebben a regiszterben kellene bekapcsolni a timer2 interruptot is:
16. oldal
DE nem teszi, így a flag soha nem lesz 1. (szerintem)
Ok, lehet én is sokat hibázok, mert felületesen nézem a kódod, de így nem lesz jó. Látom, hogy ennél a PIC-nél a timer2 másképp van, mint ahogy nálam volt. Lépésről lépésre kell haladni, főleg a PIC-nél, az nem olyan mint az Arduino.
Érdemes például Timer0, timer1 stb. függvényeket írni, ahol van init, stop, start függvény. Ezeket ki kell szervezni .c és .h fájlokba, és include-olni. Ezeket tesztelni kell keményen. Utána lehet PWM-et is előállítani ugyanígy, például PWM_init, PWM_Satart, PWM_stop függvényekkel, mert akkor a kitöltési tényezőt lehet változtatni például egy Timer0-ban is....
Ez jó lehet például az oszcillátor init-re is, amit szintén nem látok, hogy hol miképp van beállítva.
Szerintem túl sok így a hibalehetőség, persze lehet nem ez a hiba, de mintha tényleg ki lenne kapcsolva a global interrupt, ami miatt nincs flag, de tévedhetek. Illetve a PIC amit használtam külön interrupt függvényeket ad az ilyen esetekre, azaz a for(,,)-ban nem kell várni, mire oda jut a processzor. (mi ez a for(,,) pontosan?)
Hát még valami:
PORTA=0b00001001;
TRISA=0b00110111;
Fordítva kellene. Így azt gondolom jobb lenne az elejéről írni a kódot, mert lehet sok a hiba. Ha kell segítség szólj, lépésről lépésre össze lehet ezt hozni.
Ha jól látom, Timer2-t használod időzítésre is, miközben az a PWM generálásához van rendelve. Megy egyáltalán a kettő egyszerre? Dereng valami, hogy annó próbáltam valamilyen PIC-en de nagyon nem volt jó. Lehet, hogy keverem valamivel, már nem emlékszem. Próbaképpen időzítésre használd a timer1-et vagy a Timer0-át.
Kellene tudni azt is, hogy mekkora a cél-frekvencia és a kitöltési tényező (az ábra 50%-ot sugall, de tényleg annyi-e, és kell-e változatani)?
AMEGA328p esetén van olyan megoldás, hogy a számlálót úgy konfigurálod, hogy OCR1A, OCR1B egyezésnél átállítsa a kimenetet, és triggereljen interruptot (ISR( timer1_COMPA_vect), ISR( timer1_COMPB_vect)). Az interruptból pedig be lehet állítani a következő jelváltás irányát és időpontját.
Ha az IRQ futása belefér két jelváltás között, akkor ezzel a módszerrel tetszőleges jelformát ki lehet adni, az általad leírtat is.
Azt is meg lehet csinálni, hogy két különböző számlálóra állítasz be 1-1 PWM-et, és a számlálóikat úgy indítod el, hogy eltérő fázisban legyenek. Ha három dologra figyelsz, akkor reprodukálhatóan helyesen tudod állítani a fázist:
* Akkor állítsd a számláló értékét, amikor szabályos abban az értelemben, hogy nem ugrasz át eseményt.
* Az egyikből kiolvasod a számláló értéket, számolod az új értéket, és azt beállítod a másik számlálónak.
* Mindezt IRQ kizárt blokkban csinálod: ekkor mindig ugyanannyi lesz a végrehajtás ideje. Ezt vagy méred, vagy az ASM alapján számolhatod is, és ezzel az értékkel korrigálhatod, hogy mennyit adsz hozzá. De ha sima összeadással csinálod, akkor néhány órajel lesz összesen, ami 1 mikroszekundum körülre jön ki, az is lehet, hogy elhanyagolható.
Szerk.: Amit írsz úgy hangzik mintha "dead time" generátorról lenne szó, aminek az a célja, hogy H-híd esetén ne nyissuk szembe a két FET-et, ami rövidzárat jelentene. Vannak csipek, amik beípítetten tudnak dead time-ot generálni a PWM kimenethez, érdemes megfontolni, hogy olyat használj, ami eleve tudja ezt. Pl. az ATtiny1614 az adatlap szerint tudja. Ez egy újabb családba tartozik amit kicsit másképpen kell programozni. A hozzászólás módosítva: Ápr 15, 2024
Ez lenne az alapkoncepció, majd gondolkodnék azon, mi van, ha zavar van a hálózatban, vagy elszámoltam valamit, azaz időközben beüt egy másik nullátmenet. Első körben a nullátmenet beérkezésekor elindítanék mindent, majd az utolsó sorában leválasztanám a függvényt róla, azaz kikapcsolnám a detektálást. A timer2 lefutása után pedig engedném újra.
Vagy: logikai változókkal oldanám meg, azaz mindig lenne detektálás, de csak akkor indítanék timer1-et, ha a timer2 lefutását és így mindennek a kinullázását jelző változó 1. persze akkor ezt a változót a megfelelő helyeken kell beállítani és kinullázni. Így elkerülném szoftveresen, hogy ráindítson 2x. Az más kérdés, hogy utána olyan beállításokkal kellene mennie, hogy ne csak minden második félperiódusban működjön, és tényleg azt tegye amit szeretnék.
Egyelőre nem értem pontosan mert PIC-hez jobban értek, de nem minden világos miért van.
Én ilyesmin gondolkodnék:
-Nullátmenetbe: (interrupt)
Timer 1 indítása a megfelelő idő betöltésével, így az annyi idő után kapcsol be amit a kívánt teljesítmény igényel. (addig nulla ugye) Azaz 10ms-nél kisebb idővel ugye.
-Timer 1-ben: (interrupt) //Ez adná meg, melyik időben kell kapcsolni a pillanatnyi teljesítményhez
a triak lába bekapcsol, a láb magas.
timer1 kikapcsolása
timer1 kinullázása //úgyis a nullátmenet indítja el
itt indítanék egy timer2-t, ami mindig fixen ugyanannyi idő alatt fut le, ami a triak kapcsolás ideje
-Timer2-ben: (interrupt)
a triak lába kikapcsol. Ez a timer2 adja meg a triaknak szükséges impulzus hosszt.
timer2 kikapcsolása
timer2 kinullázása //Majd elindítja újra a timer1, mikor kella kakaó
Az egészre meg úgy figyelnék, hogy a timer1-be betöltendő idő nagyobb legyen, mint amit a teljesítmény igényel + a triak gyújtási ideje. + valami 1-2 mikroszek a lábak miatt, amit korábban kérdeztél.
Azaz a timer 1 időt NEM lehetne egy bizonyos szint alá vinni. Ezt kellene meghatározni, valamint azt, ha ez van, akkor mit tegyen a progi.
De lesznek nálam sokkal jobban értők is, szerintem tuti kapsz jó megoldásokat, ráadásul a tiéd is lehet jó, lehet csak én nem vágom. A hozzászólás módosítva: Márc 21, 2024
Ennyit pakoltam össze 10 perc alatt a wokwi-n, nem tudom most tesztelni.
unsigned long d4_magas_ideje;
unsigned long d5_magas_ideje;
unsigned long dt_tranzisztorok_szembenyitas;
volatile unsigned long most;
volatile unsigned long eltelt;
void setup() {
// put your setup code here, to run once:
d4_magas_ideje=5000; //microsec
d5_magas_ideje=5000; //microsec
digitalWrite(4, LOW);
digitalWrite(5, LOW);
Serial.begin(9600); // Serial connection to print samples
cli(); // disable interrupts during setup
// Configure Timer 1 interrupt
// F_clock = 16e6 Hz, prescaler = 64, Fs = 50 Hz
TCCR1A = 0;
TCCR1B = 1<<WGM12 | 0<<CS12 | 1<<CS11 | 1<<CS10;
TCNT1 = 0; // reset Timer 1 counter
// OCR1A = ((F_clock / prescaler) / Fs) - 1 = 5000-1
//Remélem ennyi, csak írtam, nem teszteltem.
OCR1A = 4999; // Set sampling frequency Fs = 50 Hz
TIMSK1 = 1<<OCIE1A; // Enable Timer 1 interrupt
sei(); // re-enable interrupts
}
// Timer 1 interrupt service routine (ISR)
ISR(timer1_COMPA_vect)
{
most=micros();
digitalWrite(4, HIGH);
while (micros-most >=d4_magas_ideje)
{
}
digitalWrite(4, LOW);
// kis idő, mielőtt szembe nyitnánk a h-hidat
most=micros();
while (micros()-most >=dt_tranzisztorok_szembenyitas)
{
}
//D5 bekapcsol
digitalWrite(5, HIGH);
most=micros();
while (micros()-most >=d5_magas_ideje)
{
}
digitalWrite(5, LOW);
//Serial.println(analogRead(0)); // Sample voltage on pin A0
}
void loop() {
// put your main code here, to run repeatedly:
}
#include <Arduino.h>
#include <TimerOne.h>
#define CLK 8
#define DIO 7
TM1637Display display (CLK, DIO );
volatile int i=0; // Variable to use as a counter volatile as it is in an interrupt
volatile boolean zero_cross=0; // Boolean to store a "switch" to tell us if we have crossed zero
int dimm;
int dim = 0;
int beolvasdelay;
const byte interruptL1= 2;
int L1_out=12;
int L2_out=3;
int L3_out=4;
int gas=5;
int preflow;
volatile boolean triggered=0;
volatile boolean uzem=0;
volatile int gas_pre=0;
int dimm_old;
int wirespeed=0;
int motorout=6;
int freqStep = 75; // This is the delay-per-brightness step in microseconds.
int current_beolvas ()
{
int ertek;
if(beolvasdelay<50){beolvasdelay++;}
else{
ertek=((analogRead(A0)+1)/3.41333);
beolvasdelay = 0;
}
return ertek;
}
bool torch_switch()
{
int torch;
torch = analogRead(A2);
if(torch>300){return 1;}
else{return 0;}
}
void kiir(int ertek, int viszony)
{
if(ertek!=viszony){
display.clear(); // Clear the display
display.showNumberDec(ertek, false); // Display the number
}
}
void zero_cross_detect() {
zero_cross = true; // set the boolean to true to tell our dimming function that a zero cross has occured
i=0;
digitalWrite(L1_out, LOW); // turn off TRIAC (and AC)
}
// Turn on the TRIAC at the appropriate time
void dim_check() {
if(zero_cross == true) {
if(i>=dim) {
if(uzem)
{digitalWrite(L1_out, HIGH);} // turn on light
i=0; // reset time step counter
zero_cross = false; //reset zero cross detection
}
else {
i++; // increment time step counter
}
}
}
void wire_speed_pwm()
{
wirespeed=(analogRead(A3)/4);
analogWrite(motorout, wirespeed);
}
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(L1_out, OUTPUT);
pinMode(gas, OUTPUT);
pinMode(motorout, OUTPUT);
display.setBrightness(7);
attachInterrupt(digitalPinToInterrupt(interruptL1), zero_cross_detect, RISING);
timer1.initialize(freqStep); // Initialize TimerOne library for the freq we need
timer1.attachInterrupt(dim_check, freqStep);
}
void loop() {
dimm_old=dimm;
dimm=current_beolvas();
dim=(113-(dimm/2.6548))+14;
preflow = analogRead(A1);
if(torch_switch())
{
gas_pre++;
digitalWrite(gas, HIGH);
}
else if (gas_pre>1)
{
gas_pre--;
}
if((preflow*2)<gas_pre)
{
if(uzem==0){gas_pre+=5;}
uzem=1;
gas_pre--;
wire_speed_pwm();
}
else
{
uzem=0;
analogWrite(motorout, 0);
}
if(gas_pre<10 && !torch_switch())
{digitalWrite(gas, LOW);}
kiir(dimm, dimm_old);
}
Ez a kódom egyenlőre, van benne sok favágó megoldás, ez az első nagyobb arduinos próbálkozásom. A cél egy CO2 hegesztő vezérlésének megvalósítása. a fő a 3 fázisos fázishasításos dimmelés megvalósítása, ez nincs még ugye meg. Van benne ezen kívül egy gáz szelep nyitás és annak az időzítése (egyik favágó megoldás) illetve egy PWM motor szabályozás ami a huzaltoló motort vezérli. Ha a fázishasítás miatt ezt a pwm vezérlést el kell engednem az nem akkora gond, meg tudom oldani máshogy is.
volatile byte allapot;
//Ebben a fggvényben lévő dolgok fognak lefutni, ha a beállított idő letelik
ISR(timer1_COMPA_vect)
{
allapot=!allapot;
if (allapot==true) {
PORTB=255;
}
else {
PORTB=0;
}
}
void setup() {
allapot=false;
cli(); // disable interrupts during setup+
// Configure Timer 1 interrupt
// F_clock = 16e6 Hz, prescaler = 64, Fs = 100 Hz
// CS12 CS11 CS10 Description
// 0 0 0 Timer stop
// 0 0 1 Prescalar=1
// 0 1 0 Prescalar=8
// 0 1 1 Prescalar=64
// 1 0 0 Prescalar=256
// 1 0 1 Prescalar=1024
// 1 1 0 Falling edge
// 1 1 1 Rising edge
TCCR1A = 0; //Mert nem kell PWM ezen
//Ez kell neked, ezt kell megérteni, az adatlapot böngészni:
TCCR1B = 1<<WGM12 | 0<<CS12 | 1<<CS11 | 1<<CS10; //CS12 ,CS12,11,10 a Prescale Binárisan számolva 1, 8, 32, 64, 128, 256, 1024 értékeket lehet beállítani
TCNT1 = 0; // reset Timer 1 counter
// OCR1A = ((F_clock / prescaler) / Fs) - 1 = 2499
OCR1A = 2499;//100Hz mert 16000000/64=250000 ez osztva a kívánt 100-Hz-el:=2500 és-1
sei(); // re-enable interrupts
Serial.begin(9600);
Serial.println("Soros Port elinditva 9600 Baoud-al.");
DDRB = DDRB | B11111111;
Serial.println("Port B kimenetre allitva. 8-13 pin");
PORTB = B00000000;
Serial.println("Port B Nullara allitva.");
TIMSK1 = 1<<OCIE1A; // Timer 1 interrupt indítása
}
void loop()
{
}
Bővebben: Link
Ide feltöltöttem, megy. A LED világít folyamatosan de nem tudja lemodellezni, no meg 100Hz-en amúgy is emberi szemmel nem látható lenne a villogás. Nekem PORT manipuláció kellett, azzal villogtatom a ledet, de 8-13 ig villogna most minden lábon.
A timer 2 szerintem hasonló. De 150Hz-re ez állítható, de ekkor az interrupt- függvényben kell a megelelő változóknak értéket adni. A hozzászólás módosítva: Jan 25, 2024
Igen, 50hz-es jelre kell a dolog, a logikát értem és köszönöm az ötletet. A kérdésem akkor már csak a kivitelezés részét érinti: egy arduino nano alkalmas e erre a feladatra? Azt tudom hogy van benne egy timer amit a delay függvény használ, illetve van benne egy timer1 nevű amit használok az első fázishoz, ezt indítja a nullátmenet és ennek a végén gyújt az első triak. A kérdésem hogy van e benne még egy timer (a netes kereséseim alapján kellene lennie) és ha igen akkor azt hogyan tudom erre felhasználni? (valami konkrét kódrészlet ha lenne az lenne a legjobb)
Üdv mindenkinek!
Egy kis segítséget szeretnék kérni egy arduinos projektben. Azzal vagyok elakadva hogy próbálok egy 3 fázisú fázishasításos dimmelést megvalósítani egy nanoval, de nem igazán tudok rájönni hogy hogyan kellene. Van az első fázison egy zero-cross figyelésem ami a D2es bemeneten egy interrupt és a timer1 segítségével azon a fázison szépen csinálja a dimmelést. Viszont nem tudom, hogy a másik két fázist hogy tudnám megfelelően megoldani, vagy hogy egyáltalán egy nano képes-e erre. Nagy segítség lenne ha valaki adna pár tippet hogy hogyan menjek tovább.
Szerintem maga a CPU altatható külső RTC nélkül is, csak az oszcillátor kell hogy működjön, meg a timer. A timer overflow (pontosan két másodpercenként), és a gombokra rakott pin change interrupt ébresztheti a CPU-t.
fotomen32-nek: Egy ATMEGA328p-t egyszer méregettem, hogy mennyit fogyaszt alvó módokban. A legfontosabb, hogy egyik láb se maradjon lebegve! Ha lebeg a láb, akkor esetleg belül változást tud indítani, és akkor fogyaszt a csip. Nem kell feltétlen külső le/felhúzó ellenállás, de a belsőt be kell álllítani a nem használt lábakra. Alapból ezek a csipek úgy működnek, hogy állapotváltozás nélkül a tranzisztorokon nem folyik áram, és nincs fogyasztásuk. A kivétel az oszcillátor és a számláló lesz, ennek menni kell. Ha a külső RTC oszcillátora hatékonyabb, mint maga a PIC, akkor lehet csak javítani azzal a hatékonyságot.
Az ADC nagy zabáló, az mindenképpen legyen lekapcsolva! Illetve minden láb legyen megfelelően bekötve és beállítva úgy, hogy statikus legyen a működés! Az ATMEGÁs mérésemnél először például elkövettem azt a hibát, hogy a VREF lábra nem kötöttem semmit és lebegni hagytam: többszörös lett a mért áram, mint az adatlapi! Ezzel azt akarom mondani, hogy akármilyen csipet is használsz, az adatlap szerint kell huzalozni ahhoz, hogy elérd a specifikáció szerinti fogyasztást.
A sonajkniz által javasolt csip adatlapjából: "Extreme Low-Power Management PIC18LF1XK22 with XLP Technology
• Sleep mode: 34 nA
• Watchdog Timer: 460 nA
• timer1 Oscillator: 650 nA @ 32 kHz"
Tehát eszerint a 684nA fogyasztást el lehet érni alvás közben, a példa is pont a kvarcórák tipikus 32kHz oszcillátorával számol. Ezt az értéket összehasonlíthatod azzal, hogy a külső RTC mit ígér, illetve ebből tudod becsülni, hogy mennyi időt fog bírni elemről. A hozzászólás módosítva: Okt 4, 2023
Ez a PIC 1,8-5,5V-ig dolgozik.
A PIC fogyasztása nagyban csökkenthető, ha alapvetően alszik, és csak 2 másodpercenként ébred timer1 által vezérelve. Ilyenkor pár villámgyors számítás, és megy vissza szunyálni, hacsak nem érzékel gombnyomást. Ha igen, kapcsolja a ledeket. A gomb elengedése után törölni kell az összes kimenetet, (még kisebb belső fogyasztás érhető el, ha altatás előtt a kimeneteket átkapcsoljuk bemenetté) majd mehet újra aludni. Persze így se számíts többéves működésre, de 6-8 hónapig azért elmegy egy 2032-essel.
Nem mondtad, hogy mi a hardvered, feltételezem, hogy valami AVR alapú Arduino lehet, például UNO. Ennek van PWM kimenete, amivel simán meg lehet valósítani ez a jelgenerátort. Viszont az Arduino könyvtárai alig-alig alkalmasak ilyesmire.
Ez az Arduinonak a nagy csapdája, hogy hiába fut mikrovezérlőn, pontos vezérlést, amire a mikrovezérlőket teremtették, azt Arduinoval nagyon nehéz megvalósítani. A szoftver nehézkesen alkalmas csak rá. A hardver viszont simán, az bőven elegendő erre a célra.
Lényegében PWM kimenetet kell használni, csak nem a kitöltési tényezőt kell állítgatni, hanem a periódusidőt, és erre elfelejtettek API-t adni az Arduino-n belül. (Ismereteim szerint, ha valaki tud rá APIt mégis az csak jó.)
Az Arduino környezeten belül is meg lehet csinálni, hogy a PWM-et nem a liben keresztül, hanem közvetlenül a regisztereket írva programozod fel. Én ezt csinálnám, akár úgy, hogy bekapcsolnám a PWM-et az Arduino libben - analogWrite funckcióval, ekkor már látsz valami működést szkópon. És utána felülírnám azokat a változókat az adatlap szerint, amivel másképpen akarom hajtani a PWM modult (Timer/Counter1). Próbálgatva kis lépésekkel lehet haladni.
Alternatív megközelítés, hogy teljesen kihagyod az analogWrite meghívását, és az adatlap szerint a regisztereket beállítva programozod fel a PWM-et.
Itt van az ATMEGA328p csip adatlapja: https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers- ATmega328P_Datasheet.pdf
Ezen belül ez a fejezet lesz érdekes: 15.9.2 Clear Timer on Compare Match (CTC) Mode. Ebben a módban hajtva az OCR1A regiszterbe kell beírni a periódusidőt és ezzel lehet állítani a periódust/frekvenciát. Tehát ezt a módot kell bekonfigurálni az adatlap szerint és után az OCR1A értékét állítgatni.
Ha már valamennyire működik, akkor még azt is meg kell csinálni, hogy mindig az átfordulás után kell beírni az értéket, amikor a számláló kicsi. Különben ha kisebbre állítjuk a határt (OCR1A) mint az előző értéke, és a számláló éppen a kettő között van amikor átírjuk, akkor lesz egy hibás teljes periódus. Ezt elkerülni a legegyszerűbben úgy lehet, hogy az OCIE1A interruptot engedélyezed, és ennek az interruptnak a kezelőjében másolod be a következő értéket. Ez az IRQ mindig 0-ra állítás után fut, tehát amikor a lehető legtöbb időnk van beállítani a határt (OCR1A). 50kHz esetén is van 320 órajelünk erre, ami bőven bőven elegendő ezen a processzoron.
Pszeudó kód a periódusidő bemásolására az OCIE1A regiszterbe:
static volatile uint16_t period=255;
loop()
{
int poti = analogRead(A0); //A poti két "vége" az ARDUINO NANO 17. lába (3,3V) és 29. lába (GND) közé, csúszkája a 19. lábára (A0) van kötve.
int freq = 100 + 76 * poti; // min "freq" = 100 Hz, max "freq" = 100 + ((76*1023*(3,3/5)) = 51 314 Hz.
uint16_t newPeriod=big_number / freq; // periódusidő kiszámolása a frekvencia alapján osztással. A big_number értékét a PWM beállításai alapján kell kiszámolni
ATOMIC_BLOCK ( ATOMIC_RESTORESTATE)
{
period = newPeriod;
}
}
ISR(timer1_COMPA_vect)
{
OCIE1A=period;
}
Az ATOMIC_BLOCK azért kell, mert 16 bites érték RAM-ba beírása nem atomi művelet.
Arra, hogy ez a proci ne lenne alkalmas ne hallgass, nagyonis alkalmas, a feladat egyáltalán nem nehéz ennek a procinak, csak korrektül kell felprogramozni. Persze az STM32 is alkalmas nyilván, ha mégis arra váltasz.
Valóban érdemes több ADC mérést csinálni és átlagolni. Az, hogy mennyire lesz zajos a mérés, az az áramkör kialakításán múlik nagymértékben, ha nem vagy profi, akkor várhatóan bizony zajos lesz...
Szerk.: ahhoz, hogy a 16 bites tartomány elegendő legyen a periódusidő kifejezéséhez, az osztót /8-ra kell állítani ( TCCR1B CS bitjei). Így 40-20000 között lesz a periódusidő az igényelt frekvenciákhoz. A hozzászólás módosítva: Aug 18, 2023
ATMEGA timer1 moduljával meg tudom csinálni.
Az USDX rádiót szerintem érdemes lenne megépíteni ATMEGA2560 kontrollerrel.
Több láb, memória, ami szerintem zavaró az USDX -nél hogy a hang 8 bites, így én nem érteni a beszédit, pedig az A/D konverter 10 bites, illetve a számolásokat 16 biten végzi, de csak a timer1 alsó 8 bitje van használva fast PWM módban, a jel osztva 32-vel nem, tudom miért nem a 10 bites módban használják, valószínűleg lassúbb.
Nem lenne jobb egy külső DAC például MCP4921 ?
Valahogy így:
OCR1AL = min(max((ozi2>>5) + 128, 0), 255);
helyett:
int DACOUT = min(max((ozi2) + 2048, 0), 4095);
SPDR = (DACOUT >> 8)|0x30;
SPDR = DACOUT & 0x00FF;
Egész pontosan:
// Timer 1 interrupt service routine (ISR)
ISR(timer1_COMPA_vect)
{
PORTB=(szin_tabla[index]);
index+=increment;
}
Üdv!
Akkor jók lehetnek a kijelzések, de ezt a kódot nem értem pontosan. Az idő nem lesz pontos. Miért nem használsz timert? Az pontosabb lehet, mert a fenti kódodban a műveletek elvégzéséhez időre van szüksége az mcu-nak. Volatile változót növelhetsz, ha a timer beüt. Elvileg az Atmega is tud olyat, hogy a Timer valmilyen kezdőértékről indulva fusson. Azt beállítva lehet pontosítani még. Bár az IDE erre nem nagyon alkalmas.
if (timer == 1){
sec = sec + 1;
delay(1000); //Ez nem vágja agyon a hardveres timert????
Bár itt van timer, de nem tudom az pontosan micsoda, de a delay tuti nem a legjobb ide. Vagy még jobb megoldás az RTC modul használata lenne.
Itt valamiről beszélgetnek:
Bővebben: Link
A PIC-nél (annak sem pontos a pll-je) úgy kell beállítani a timert, hogy a fő oszcillátort le lehet osztani kettő hatvényaival. Azaz pl 64-el. Feltéve, ha az Arduino 16MHz-en fut, akkor 0.25MHz-en fut a timer 64 -es leosztás mellett. Ha a timer 66535-ig tud számiolni, akkor a túlcsordulás kb 0.27s -enként történik. Ez nem elég, de le lehet osztani többel is:
3. Available division factors:
CS12 - CS10 = 000 : no clock source TC1 is OFF
CS12 - CS10 = 001 : divide by 1
CS12 - CS10 = 010 : divide by 8
CS12 - CS10 = 011 : divide by 64
CS12 - CS10 = 100 : divide by 256
CS12 - CS10 = 101 : divide by 1024
Ha 256-al osztod, akkor már több mint 1s. Az jó. Ha tudod, hogy 16/256MHz (62500Hz)-en számol a timer és tudod, hogy ha 16 bites a timer (saccolom, remélem ennyi) akkor 65535-62500=3035-ről kell indtani. A PIC-nél lehet tudni, hogy maga a beállítás mennyi órajelbe telik, azt le lehet vonni. De 256 prescale-nél mát más lehet a dolog...
Szóval, ha pontos külső 16MHz-es kvarcról hajtod, még pontos is lehet.
De lehet ezt is csinálod, de akkor a delay-t nem értem...
(#) |
wbt hozzászólása |
Dec 6, 2022 |
Sziasztok!
Frekvenciagenerátorhoz timer1-el állítgatnom kellene az előosztót.
--------------------------------------
(P-frekvencia Hz-ben van és TOGGLE a kimenet, de ez most nem érdekes)
Select Case P_frekvencia
Case Is >= 123:
A = Tccr1b
A = A And &B1111_1000
A = A Or &B0000_0001 'Előosztó=1
P_oszto = 8000000 / P_frekvencia
Case 16 To 122:
A = Tccr1b
A = A And &B1111_1000
A = A Or &B0000_0010 'Előosztó=8
P_oszto = 1000000 / P_frekvencia
Case Is < 16:
A = Tccr1b
A = A And &B1111_1000
A = A Or &B0000_0011 'Előosztó=64
P_oszto = 125000 / P_frekvencia
End Select
Tccr1b = A
Temp_w = Loww(p_oszto) '16bit
Compare1a = Temp_w
Compare1b = Temp_w
Start timer1
-------------------------------------------------------------------------------------
Hiába írom a TCCR1B regisztert, nem történik semmi ![](/pic/smile/sad.gif)
Mit néztem be?
(alsó 3 bit az előosztó)
Attól függ, milyen PIC-ről beszélünk. PWM-et le leht állítani úgy is, hogy adott lábat bemenetre kapcsolod. Az új kontrollerekben ott a bővített tudású Timer2, kapuzható timer1, CLC, NCO modulok stb. Csak fantázia kérdése.
Miért nem direkt a PWM jelet méred? timer1/3/5 module with gate control, vagy újabb kontrollerekben SMT - Signal Measurement Timer.
Dear friend, hardware testing is time taking and little hard job and remote in proteus is not functioning perfectly, please let me know if we attached two toggle swiches on free port as shown in attached screen shot,port RC0 SW1 is for ON and port RC2 SW2 is for OFF for triac2, then what ia modification in codes in main.c, if it is possible then i can test in proteus simulation software,
PLEASE MODIFY THE CODES: /********************************************************************************
* Fan Controller *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
* Date : Friday, 21 January 2011 *
* Author : C.V.Niras/VU3CNS *
* Copyright : (C) 2010 C. V. Niras *
* Email : cvniras@gmail.com *
* Processor : 12F675 *
* First Release : 23/01/2011 *
* Ver : 0.7 *
* Change History: *
* Rev Date Description *
* 0.5 06/03/2011 First stable release *
* 0.6 08/03/2011 Bug fixed - Can't swich on by CH+, when turned *
* off by set speed to 0 *
* 0.7 14/06/2011 Trigger off delayed for full speed (low firing *
* angle) to reach the TRIAC latch current *
* *
*********************************************************************************/
#include <pic.h>
#include "type_def.h"
#include "remote_commands.h"
#if defined _12F675
__CONFIG(WDTDIS & MCLRDIS & INTIO & BORDIS & UNPROTECT & PWRTEN);
#define IsIRDataBitHigh() GPIO3 == 0 // Inverted logic
#define SW_UP _GPIO,0 // Up switch
#define SW_DN _GPIO,2 // Down switch
#define LEDOn() GPIO1 = 1 // LED
#define LEDOff() GPIO1 = 0
#define TriacOn() GPIO5 = 0 // Triac
#define TriacOff() GPIObits.GPIO5 = 1
#define TRIAC GPIO5 // Triac pin
#endif
#if defined _16F676
__CONFIG(WDTDIS & MCLRDIS & INTOSCIO & BORDIS & UNPROTECT & PWRTEN);
#define GPIO PORTA
#define TRISIO TRISA
#define GPIF RAIF
#define GPIE RAIE
#define IsIRDataBitHigh() PORTAbits.RA3 == 0 // Inverted logic
#define SW_UP _PORTA,0 // Up switch
#define SW_DN _PORTA,2 // Down switch
#define LEDOn() PORTAbits.RA1 = 1 // LED
#define LEDOff() PORTAbits.RA1 = 0
#define TriacOn() PORTAbits.RA5 = 0 // Triac
#define TriacOff() PORTAbits.RA5 = 1
#define TRIAC PORTAbits.RA5 // Triac pin
// v Added to handle triac2
#define Triac2On() PORTCbits.RC5 = 0 // Triac2
#define Triac2Off() PORTCbits.RC5 = 1
#define TRIAC2 PORTCbits.RC5
// ^ Added to handle triac2
#endif
__EEPROM_DATA(5, 1, 1, 255, 255, 255, 255, 255);
__IDLOC7('0','.','7','B');
#define TIMER_ENABLE // Enable timer
// -- Chip Configurations --
#define _XTAL_FREQ 4000000
#define ZC_PIN_MASK 0x10 // Pin used for zero cross detection
#define IR_PIN_MASK 0x08 // IR sensor output
#define TIME_COUNT 6866 // Number of timer1 overflows in an hour
#define ANY_KEY Key & 0x80
#define UP_KEY Key & 0x01
#define DN_KEY Key & 0x02
// Timer 1 is the time base, 1 bit time = 8us; the NEC physical bit time is 560us = 70 Timer 1
// The following time are set with a +/- 20% tolerance
#define IR_MARK_MIN_TIME 787
#define IR_SPACE_MIN_TIME 219
#define MIN_IR_BIT_TIME 56
#define MAX_IR_BIT_TIME 84
// -- End of Chip Configurations --
#define IRRx Flag.b0 // New IR bit received
#define IRNewHit Flag.b1 // A new IR command received
#define Error Flag.b2 // General error flag
#define IRCmdRepeat Flag.b3 // A IR repeat command received
#define StartFan Flag.b4 // Indicate to start the fan
#define EEPromWrite Flag.b5 // Indicate to write to EEPROM
#define UnknownCmd Flag.b6 // Unused IR command
#define EETimeUpdate Flag1.b0 // Indicate to update time in eeprom
#define IR05Seconds Flag1.b1 // A 0.5 seconds of IR inactivity, used to clear IR command repeate flag
#define ClearLED Flag1.b2 // Need to turn off LED
#define FanOn Status.b0 // Fan Running
#define TimerRunning Status.b1 // Timer Running
#define AddZeroToIRData() IRData._dword >>= 1 // Add a 0 bit to IR data
#define AddOneToIRData() IRData._dword >>= 1; IRData._dword |= 0x80000000 // Add a 1 bit to IR data
// NEC IR protocol states
typedef enum _NEC_STATES
{
IR_IDLE,
IR_MARK,
IR_SPACE,
IR_HIGH,
IR_LOW,
IR_REPEAT
} NEC_STATES;
// V A R I A B L E S
//const unsigned char STable[10] = {0, 157, 165, 173, 181, 188, 195, 205, 216, 252};
// Modified to latch low power (load) fans low firing angle (on full speed)
const unsigned char STable[10] = {0, 157, 165, 173, 181, 188, 195, 205, 216, 234};
near volatile BYTE Flag, Flag1, Status;
near NEC_STATES IRState;
unsigned char IRDataCount, PhaseAngle, Speed, Time, Count;
volatile near unsigned char EECounter, Ticks, Key, KeyCount;
volatile unsigned int IRTime, TimeCounter;
DWORD IRData;
// F U N C T I O N P R O T O T Y P E S
void IRHandler(void);
void NECDecoder(void);
void InitIR(void);
void SetSpeed(void);
void OffTimer(void);
void OnTimer(void);
void SetTimer(void);
void GetEEVariables(void);
void SetEEVariables(void);
void KeyDelay(void);
void interrupt isr(void);
void Delay2s(void);
// M A I N
void main(void)
{
#asm
call 0x3ff
bsf STATUS, 5
movwf OSCCAL & 0x7f
bcf STATUS, 5
#endasm
GPIO = 0; // Clear PORT
// v Added to handle triac2
PORTC = 0;
// ^ Added to handle triac2
TriacOff(); // Triac off
TRISIO = ZC_PIN_MASK | IR_PIN_MASK | 0x05; // IR, Zero cross and swiches
// v Added to handle triac2
TRISC = 0;
// ^ Added to handle triac2
WPU = 0x05; // Weak pull up enabled for wwitches
IOC = ZC_PIN_MASK | IR_PIN_MASK; // Interrupt on change is enabled for GPIO2, GPIO4
ANSEL = 0x00; // All are digital i/o
CMCON = 0x07; // Comparators off
INTCON = 0x68; // Enable PEIE, Timer0, Port change interrupts
OPTION_REG = 0x05; // INT falling edge, Prescaler 1:64
T1CON = 0x31; // Prescaler 1:8, internal clk, TMR1ON
LEDOn();
Flag._byte = 0; // Initialise flags and variables
Flag1._byte = 0;
InitIR();
GetEEVariables(); // Read variables eeprom
IRState = IR_IDLE; // Init IR state
if(FanOn)
StartFan = 1;
FanOn = 0; // This created a fresh start
#ifdef TIMER_ENABLE
if(TimerRunning) // If already started, set the time again
SetTimer();
#endif
GIE = 1; // Enable interrupts
SetSpeed(); // Set the speed
LEDOff(); // Turn off LED
Count = Time << 1; // Count = Time * 2, i.e turn on/off
Ticks = 0;
do
{
NECDecoder(); // Decode NEC formatted IR data
if(IRNewHit) // Is any new data?
{
IRNewHit = 0; // Y. Clear flag
IRHandler(); // Do the command
}
if(IRCmdRepeat) // As long as the repeat command present
{ // do not turn of LED
IRCmdRepeat = 0;
Ticks = 0; // for the same clear Ticks
}
if(EEPromWrite)
{
EEPromWrite = 0; // Clear eeprom update flag
SetEEVariables(); // Write variables if necessory
}
if(ClearLED)
{
if(Ticks & 0x20) // If remote command received, turn off LED after only
{ // few ms (~320ms)
ClearLED = 0;
LEDOff();
}
}
#ifdef TIMER_ENABLE
else if(TimerRunning && (Ticks & 0x40)) // If timer is running and a short time expired (640ms)
{ // used to blink LED to show the time remaining
if(Count == 0xF7) // Reload counter to show the time, after a certain time gap
{
Count = Time << 1; // Count = Time * 2, i.e turn on/off
LEDOff(); // Ensure LED is off
}
if(!(--Count & 0x80)) // Blinks the LED till counter become -ve
{
if(Count & 0x01) { // On odd numbers in counter LED on
LEDOn();
}
if(!(Count & 0x01)) { // For even numbers LED off
LEDOff();
}
}
Ticks = 0; // Reset ticks
}//if(TimerRunning && (Ticks & 0x40))
#endif
if(KeyCount >= 4) // Has key pressed for a short time?
{
if(UP_KEY) // Y. Check for Up key press
{
StartFan = 1; // Y. Up key pressed, inc the speed
Speed++;
}
if(DN_KEY) // Check for a down key press
{
StartFan = 1; // Y. Down key pressed, decrement the speed
Speed--;
}
if(StartFan) // If any key pressed, do the action
{
SetSpeed();
KeyDelay(); // Give a delay beore the next check
}
}
}while(1);
}// main
// F U N C T I O N S
/**
The function is used to decode IR commands and make changes required
*/
void IRHandler(void)
{
if(!(IRData.byte0 ^ IRData.byte1) == 0) // Address and its compliment match
{
if(IRData.byte0 == 0) // Address is zero
{
if(!(IRData.byte2 ^ IRData.byte3) == 0) // Command and its compliment match
{
UnknownCmd = 0;
switch(IRData.byte2)
{
case VOL_PLUS:
StartFan = 1;
Speed++;
break;
case VOL_MINUS:
StartFan = 1;
Speed--;
break;
case DIGIT0:
Speed = 0;
OffTimer();
break;
case DIGIT1:
StartFan = 1;
Speed = 1;
break;
case DIGIT2:
StartFan = 1;
Speed = 2;
break;
case DIGIT3:
StartFan = 1;
Speed = 3;
break;
case DIGIT4:
StartFan = 1;
Speed = 4;
break;
case DIGIT5:
StartFan = 1;
Speed = 5;
break;
case DIGIT6:
StartFan = 1;
Speed = 6;
break;
case DIGIT7:
StartFan = 1;
Speed = 7;
break;
case DIGIT8:
StartFan = 1;
Speed = 8;
break;
case DIGIT9:
StartFan = 1;
Speed = 9;
break;
case CH_MINUS:
FanOn = 0;
OffTimer();
break;
case CH_PLUS:
if(Speed == 0) Speed++;
StartFan = 1;
break;
case PREV:
if(FanOn) Time--;
SetTimer();
break;
case NEXT:
if(FanOn) Time++;
SetTimer();
break;
case EQ:
OffTimer();
break;
case PLAY:
OnTimer();
break;
// v Added to handle triac2
case CH100:
Triac2On();
break;
case CH200:
Triac2Off();
break;
// ^ Added to handle triac2
default:
UnknownCmd = 1;
break;
}
if(!UnknownCmd){
LEDOn(); // A new command received
ClearLED = 1; // Clear LED after a little time
Ticks = 0; // Reset timer ticks
SetSpeed();
}
}// if((IRData.byte0 ^ IRData.byte1) == 0)
}// if(IRData.byte3 == 0)
}//if((IRData.byte3 ^ IRData.byte2) == 0)
}
/**
Off the timer, without changing previous set time
*/
void OffTimer(void)
{
TimerRunning = 0; // Turn off timer
Time = eeprom_read(1); // Read the eeprom, value
EETimeUpdate = 1; // Update time in the eeprom
EECounter = 0; // Clear the eeprom counter to update eeprom
}
/**
On timer, start with the previous set time, if the timer is not running
*/
void OnTimer(void)
{
if(FanOn == 1) // Only start Timer when fan on
{
if(!TimerRunning) // Nothing to do if already started
{
TimerRunning = 1; // Start the timer
Time = eeprom_read(1); // Get time eeprom
if(Time == 0) // If zero, switch on timer with a non zero value, i.e one hour
Time++;
TimeCounter = TIME_COUNT; // Reload the counter
EETimeUpdate = 1; // Update time in the eeprom
EECounter = 0; // Clear the eeprom counter to update eeprom
}
}
}
/**
Set the counters for the timer. When the counter reached zero, the fan will be turned off
If the timer not running, it reload time value with the last saved value the eeprom,
otherwise adjust counters as required, and clear eeprom counter to update time value in the
eeprom, for the same it set a EETimeUpdate flag
*/
void SetTimer(void)
{
if(Time & 0x80) // A neg, so clear it
Time = 0;
if(Time > 8)
Time = 8; // Max 8 hours
if(FanOn == 0) // Nothing to do if fan is not running
return;
if(!TimerRunning && (Time != 0)) { // If decrementing, and time reached zero, on further
Time = eeprom_read(1); // decrements never start the timer, only start on
TimerRunning = 1; // increments, i.e when time not zero.
if(Time == 0) // If zero, start with a non zero value
Time++; // i.e. set to one
}
if(Time == 0) // Stop timer, if time is zero
TimerRunning = 0;
TimeCounter = TIME_COUNT; //
EETimeUpdate = 1; // Update time in the eeprom
EECounter = 0; // Clear the eeprom counter to update eeprom
}
/**
Set the speed and update phase angle for a given speed. If start fan flag is set, and fan not running
it starts fan will full speed for a second, then changes to ed speed.
*/
void SetSpeed(void)
{
if(Speed & 0x80) // A neg, keep it as zero
Speed = 0;
if(Speed >= 10) // Reach the max.
Speed = 9;
if(Speed == 0){
StartFan = 0; // For a zero speed, switch off
FanOn = 0;
}
if(StartFan){ // If required, try to start the fan
if(!FanOn){ // Already running?
FanOn = 1; // No. Switch on fan
PhaseAngle = STable[9]; // If just swiched on run it on full speed
Delay2s(); // for a short time
}
StartFan = 0; // Clear the flag
}
if(FanOn == 0) OffTimer();
PhaseAngle = STable[Speed]; // Set the phase angle for the speed
EECounter = 0; // Update EEPROM
}
/**
Decode the IR data received in NEC format
*/
void NECDecoder(void)
{
static unsigned int IRBitTime, PrevIRTimer;
#if 0
static unsigned char Port;
if((Port ^ GPIO) & IR_PIN_MASK) // IR line changed
{
*((unsigned char*)&IRTime) = TMR1L; // Copy the current Timer 1 value (LSB)
*((unsigned char*)&IRTime + 1) = TMR1H; // -- do -- (MSB)
Port = GPIO;
IRBitTime = IRTime - PrevIRTimer;
PrevIRTimer = IRTime;
if(IRBitTime & 0x0800)
IRState = IR_IDLE; // Idle for more than 16 ms
IRRx = 0;
#else
if(IRRx)
{
IRBitTime = IRTime - PrevIRTimer;
PrevIRTimer = IRTime;
if(IRBitTime & 0x0800)
IRState = IR_IDLE; // Idle for more than 16 ms
IRRx = 0;
#endif
Error = 0;
switch(IRState)
{
case IR_IDLE:
if(IsIRDataBitHigh()) // If it is a one, IR starting
IRState++; // Now is IR_MARK
IRDataCount = 0;
IRData._dword = 0;
break;
case IR_MARK: // Now IR Mark just over
if(IRBitTime < IR_MARK_MIN_TIME)
{
Error = 1; // Less than specified mark time
}
IRState++;
break;
case IR_SPACE: // Now IR space just over
if(IRBitTime < IR_SPACE_MIN_TIME)
{
Error = 1; // Less than specified space time
}
if(IRBitTime < IR_SPACE_MIN_TIME * 2)
{
IRState = IR_REPEAT; // If it is less than 4.5 ms, it may be a repeat command
break;
}
IRState++; // Space is 4.5 ms, now IR high
break;
case IR_HIGH: // IR high just over, check it
if(((unsigned char) IRBitTime < MIN_IR_BIT_TIME) || ((unsigned char) IRBitTime > MAX_IR_BIT_TIME))
{
Error = 1; // Too short or too long pulse
}
IRState++;
break;
case IR_LOW: // IR low just over, check it
if(((unsigned char) IRBitTime < MIN_IR_BIT_TIME) || ((unsigned char) IRBitTime > MAX_IR_BIT_TIME * 3))
{
Error = 1; // Too short or too long pulse
}
if((unsigned char) IRBitTime >= MIN_IR_BIT_TIME * 3)
{
AddOneToIRData(); // Longer low time, add a one
}
else
{
AddZeroToIRData(); // Short low time add a zero
}
IRDataCount++; // Increment the counter
IRState--; // Now is IR High
break;
case IR_REPEAT: // In repeat, the 560us IR burst just over, check it now
if(((unsigned char) IRBitTime < MIN_IR_BIT_TIME) || ((unsigned char) IRBitTime > MAX_IR_BIT_TIME))
{
IRCmdRepeat = 0;
Error = 1;
}
IRCmdRepeat = 1;
IRState = IR_IDLE;
break;
}// switch(IRState)
if(Error)
{
InitIR();
}
if(IRDataCount == 32)
{
IRNewHit = 1;
IRState = IR_IDLE;
IRDataCount = 0;
//IROff = 0;
}
IR05Seconds = 0;
}// if(IRRx)
}
/**
Initialise IR states
*/
void InitIR( void ) // initial IR engine
{
IRState = IR_IDLE;
IRNewHit = 0;
IRCmdRepeat = 0;
IRDataCount = 0;
}
/**
Read variables eeprom
*/
void GetEEVariables(void)
{
Speed = eeprom_read(0);
Time = eeprom_read(1);
Status._byte = eeprom_read(2);
}
/**
Write to eeprom, the variables
*/
void SetEEVariables(void)
{
// Compare with the eeprom variables and update if necessory
if(Speed != eeprom_read(0))
eeprom_write(0, Speed);
if(EETimeUpdate) // Time may change while running, so only update
{ // if user make changes
if(Time != eeprom_read(1))
eeprom_write(1, Time);
EETimeUpdate = 0;
}
if(Status._byte != eeprom_read(2))
eeprom_write(2, Status._byte);
}
/**
Create a 2 seconds delay, used to start the fan
*/
void Delay2s(void)
{
unsigned char Count;
Count = 200; // Make a 200 x 10 ms delay
while(--Count != 0)
__delay_ms(10);
}
/**
Delay after a key press. This function retuns after a specified time or when no key pressed down
*/
void KeyDelay(void)
{
unsigned char ms;
ms = 250; // 500 ms delay
do
{
if(!ANY_KEY) // If key released, return
break;
__delay_ms(2);
}while(--ms != 0);
}
void interrupt isr(void)
{
static unsigned char PortStatus, PortChanges;
if(GPIF)
{
PortChanges = PortStatus; // Copy the previous value
PortStatus = GPIO; // Update PortStatus
GPIF = 0; // Clear interrrupt
PortChanges ^= PortStatus; // Find the differences
if(PortChanges & ZC_PIN_MASK) // Zero cross
{
TMR0 = PhaseAngle; // Phase angle is controlled via TMR0, on interrupt it trigger
if(FanOn && (PhaseAngle >= STable[9])){ // For full speed hold trigger now, and TMR0 interrupt (delayed
TriacOn(); // to reach TRIAC holding current) clear the trigger
}
Ticks++; // Ticks @ 10 ms
{
#asm
INCFSZ _KeyCount,W // Inc Key Count, but not beyond 255
MOVWF _KeyCount
CLRW // Clear W
BTFSS SW_UP // Up Key pressed?
MOVLW 0x81 // Y. Load W with 0x81
BTFSS SW_DN // Down Key pressed?
MOVLW 0x82 // Y. Load W with 0x82
MOVWF _Key // Save W to Key
BTFSS _Key,7 // Has any key pressed?
CLRF _KeyCount // N. Clear the counter
#endasm
}
}//if(PortChanges & ZC_PIN_MASK)
if(PortChanges & IR_PIN_MASK) // IR line changed
{
*((unsigned char*)&IRTime) = TMR1L; // Copy the current Timer 1 value (LSB)
*((unsigned char*)&IRTime + 1) = TMR1H; // -- do -- (MSB)
IRRx = 1;
}
}
if(T0IF) // Interrupt depends on phase angle (TMR0 is set by phase angle)
{
if(FanOn){
TriacOn(); // Triac triggered
}
T0IF = 0; // Clear flag
NOP();
NOP();
NOP();
NOP();
TriacOff(); // Triac off, beacuse already triggered
}//if(T0IF)
if(TMR1IF) // @ 524ms; This interrupt is not set, but polled
{ // with other interrupts
TMR1IF = 0;
#ifdef TIMER_ENABLE
if(TimerRunning && (--TimeCounter == 0)) // If timer running, decrement counter
{
TimeCounter = TIME_COUNT; // Reload counter
if(--Time == 0) // The time expired, switch off fan and counter
{
OffTimer(); // Switch off timer
FanOn = 0;
}
}
#endif
{
#asm
INCFSZ _EECounter,W // Inc eeprom timer, but not beyond 255
MOVWF _EECounter
#endasm
}
if(EECounter == 8) // After 4 seconds since clearing the counter
EEPromWrite = 1; // set eeprom write flag
if(IR05Seconds) // After 0.5 seconds of inactivity
IRCmdRepeat = 0; // clear the repeat command
IR05Seconds = 1;
}//if(TMR1IF)
}
Again Thank you A hozzászólás módosítva: Jún 24, 2022
timer1, ha nem használod, elvileg nem szólhat bele. A T1CON regiszter értéke Reset után 0x00. Ha használod, akkor bit 7-6 ne legyen 0b10, valamint bit 3 ne legyen 0b1.
Az RA5 elvileg nem lehet analóg bemenet, így azt a bitet át sem lehet állítani. Már csak az RA5-re vonatkozó regiszter marad, ami Reset után egyébként is 0b1:
TRISAbits.TRISA5=1;
Ha nem valamilyen hipertitkor projekt, töltsd fel a kódot, több szem többet lát.
Ezen kívűl a timer1 bemenete is lehet az RA5. Adatlap 172. oldaltól olvasd el.
Dear Sir, I need your help again, I have the codes to control the traic to control the speed of fan using 16F676 schematic 1 working successfully and codes attached below, now I want some amendment in codes to toggle control one more triac on another port as schematic 2 attached below, Please help me /********************************************************************************
* Fan Controller *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
* Date : Friday, 21 January 2011 *
* Author : C.V.Niras/VU3CNS *
* Copyright : (C) 2010 C. V. Niras *
* Email : cvniras@gmail.com *
* Processor : 12F675 *
* First Release : 23/01/2011 *
* Ver : 0.7 *
* Change History: *
* Rev Date Description *
* 0.5 06/03/2011 First stable release *
* 0.6 08/03/2011 Bug fixed - Can't swich on by CH+, when turned *
* off by set speed to 0 *
* 0.7 14/06/2011 Trigger off delayed for full speed (low firing *
* angle) to reach the TRIAC latch current *
* *
*********************************************************************************/
#include <pic.h>
#include "type_def.h"
#include "remote_commands.h"
#if defined _12F675
__CONFIG(WDTDIS & MCLRDIS & INTIO & BORDIS & UNPROTECT & PWRTEN);
#define IsIRDataBitHigh() GPIO3 == 0 // Inverted logic
#define SW_UP _GPIO,0 // Up switch
#define SW_DN _GPIO,2 // Down switch
#define LEDOn() GPIO1 = 1 // LED
#define LEDOff() GPIO1 = 0
#define TriacOn() GPIO5 = 0 // Triac
#define TriacOff() GPIObits.GPIO5 = 1
#define TRIAC GPIO5 // Triac pin
#endif
#if defined _16F676
__CONFIG(WDTDIS & MCLRDIS & INTOSCIO & BORDIS & UNPROTECT & PWRTEN);
#define GPIO PORTA
#define TRISIO TRISA
#define GPIF RAIF
#define GPIE RAIE
#define IsIRDataBitHigh() PORTAbits.RA3 == 0 // Inverted logic
#define SW_UP _PORTA,0 // Up switch
#define SW_DN _PORTA,2 // Down switch
#define LEDOn() PORTAbits.RA1 = 1 // LED
#define LEDOff() PORTAbits.RA1 = 0
#define TriacOn() PORTAbits.RA5 = 0 // Triac
#define TriacOff() PORTAbits.RA5 = 1
#define TRIAC PORTAbits.RA5 // Triac pin
#endif
__EEPROM_DATA(5, 1, 1, 255, 255, 255, 255, 255);
__IDLOC7('0','.','7','B');
#define TIMER_ENABLE // Enable timer
// -- Chip Configurations --
#define _XTAL_FREQ 4000000
#define ZC_PIN_MASK 0x10 // Pin used for zero cross detection
#define IR_PIN_MASK 0x08 // IR sensor output
#define TIME_COUNT 6866 // Number of timer1 overflows in an hour
#define ANY_KEY Key & 0x80
#define UP_KEY Key & 0x01
#define DN_KEY Key & 0x02
// Timer 1 is the time base, 1 bit time = 8us; the NEC physical bit time is 560us = 70 Timer 1
// The following time are set with a +/- 20% tolerance
#define IR_MARK_MIN_TIME 787
#define IR_SPACE_MIN_TIME 219
#define MIN_IR_BIT_TIME 56
#define MAX_IR_BIT_TIME 84
// -- End of Chip Configurations --
#define IRRx Flag.b0 // New IR bit received
#define IRNewHit Flag.b1 // A new IR command received
#define Error Flag.b2 // General error flag
#define IRCmdRepeat Flag.b3 // A IR repeat command received
#define StartFan Flag.b4 // Indicate to start the fan
#define EEPromWrite Flag.b5 // Indicate to write to EEPROM
#define UnknownCmd Flag.b6 // Unused IR command
#define EETimeUpdate Flag1.b0 // Indicate to update time in eeprom
#define IR05Seconds Flag1.b1 // A 0.5 seconds of IR inactivity, used to clear IR command repeate flag
#define ClearLED Flag1.b2 // Need to turn off LED
#define FanOn Status.b0 // Fan Running
#define TimerRunning Status.b1 // Timer Running
#define AddZeroToIRData() IRData._dword >>= 1 // Add a 0 bit to IR data
#define AddOneToIRData() IRData._dword >>= 1; IRData._dword |= 0x80000000 // Add a 1 bit to IR data
// NEC IR protocol states
typedef enum _NEC_STATES
{
IR_IDLE,
IR_MARK,
IR_SPACE,
IR_HIGH,
IR_LOW,
IR_REPEAT
} NEC_STATES;
// V A R I A B L E S
//const unsigned char STable[10] = {0, 157, 165, 173, 181, 188, 195, 205, 216, 252};
// Modified to latch low power (load) fans low firing angle (on full speed)
const unsigned char STable[10] = {0, 157, 165, 173, 181, 188, 195, 205, 216, 234};
near volatile BYTE Flag, Flag1, Status;
near NEC_STATES IRState;
unsigned char IRDataCount, PhaseAngle, Speed, Time, Count;
volatile near unsigned char EECounter, Ticks, Key, KeyCount;
volatile unsigned int IRTime, TimeCounter;
DWORD IRData;
// F U N C T I O N P R O T O T Y P E S
void IRHandler(void);
void NECDecoder(void);
void InitIR(void);
void SetSpeed(void);
void OffTimer(void);
void OnTimer(void);
void SetTimer(void);
void GetEEVariables(void);
void SetEEVariables(void);
void KeyDelay(void);
void interrupt isr(void);
void Delay2s(void);
// M A I N
void main(void)
{
#asm
call 0x3ff
bsf STATUS, 5
movwf OSCCAL & 0x7f
bcf STATUS, 5
#endasm
GPIO = 0; // Clear PORT
TriacOff(); // Triac off
TRISIO = ZC_PIN_MASK | IR_PIN_MASK | 0x05; // IR, Zero cross and swiches
WPU = 0x05; // Weak pull up enabled for wwitches
IOC = ZC_PIN_MASK | IR_PIN_MASK; // Interrupt on change is enabled for GPIO2, GPIO4
ANSEL = 0x00; // All are digital i/o
CMCON = 0x07; // Comparators off
INTCON = 0x68; // Enable PEIE, Timer0, Port change interrupts
OPTION_REG = 0x05; // INT falling edge, Prescaler 1:64
T1CON = 0x31; // Prescaler 1:8, internal clk, TMR1ON
LEDOn();
Flag._byte = 0; // Initialise flags and variables
Flag1._byte = 0;
InitIR();
GetEEVariables(); // Read variables eeprom
IRState = IR_IDLE; // Init IR state
if(FanOn)
StartFan = 1;
FanOn = 0; // This created a fresh start
#ifdef TIMER_ENABLE
if(TimerRunning) // If already started, set the time again
SetTimer();
#endif
GIE = 1; // Enable interrupts
SetSpeed(); // Set the speed
LEDOff(); // Turn off LED
Count = Time << 1; // Count = Time * 2, i.e turn on/off
Ticks = 0;
do
{
NECDecoder(); // Decode NEC formatted IR data
if(IRNewHit) // Is any new data?
{
IRNewHit = 0; // Y. Clear flag
IRHandler(); // Do the command
}
if(IRCmdRepeat) // As long as the repeat command present
{ // do not turn of LED
IRCmdRepeat = 0;
Ticks = 0; // for the same clear Ticks
}
if(EEPromWrite)
{
EEPromWrite = 0; // Clear eeprom update flag
SetEEVariables(); // Write variables if necessory
}
if(ClearLED)
{
if(Ticks & 0x20) // If remote command received, turn off LED after only
{ // few ms (~320ms)
ClearLED = 0;
LEDOff();
}
}
#ifdef TIMER_ENABLE
else if(TimerRunning && (Ticks & 0x40)) // If timer is running and a short time expired (640ms)
{ // used to blink LED to show the time remaining
if(Count == 0xF7) // Reload counter to show the time, after a certain time gap
{
Count = Time << 1; // Count = Time * 2, i.e turn on/off
LEDOff(); // Ensure LED is off
}
if(!(--Count & 0x80)) // Blinks the LED till counter become -ve
{
if(Count & 0x01) { // On odd numbers in counter LED on
LEDOn();
}
if(!(Count & 0x01)) { // For even numbers LED off
LEDOff();
}
}
Ticks = 0; // Reset ticks
}//if(TimerRunning && (Ticks & 0x40))
#endif
if(KeyCount >= 4) // Has key pressed for a short time?
{
if(UP_KEY) // Y. Check for Up key press
{
StartFan = 1; // Y. Up key pressed, inc the speed
Speed++;
}
if(DN_KEY) // Check for a down key press
{
StartFan = 1; // Y. Down key pressed, decrement the speed
Speed--;
}
if(StartFan) // If any key pressed, do the action
{
SetSpeed();
KeyDelay(); // Give a delay beore the next check
}
}
}while(1);
}// main
// F U N C T I O N S
/**
The function is used to decode IR commands and make changes required
*/
void IRHandler(void)
{
if(!(IRData.byte0 ^ IRData.byte1) == 0) // Address and its compliment match
{
if(IRData.byte0 == 0) // Address is zero
{
if(!(IRData.byte2 ^ IRData.byte3) == 0) // Command and its compliment match
{
UnknownCmd = 0;
switch(IRData.byte2)
{
case VOL_PLUS:
StartFan = 1;
Speed++;
break;
case VOL_MINUS:
StartFan = 1;
Speed--;
break;
case DIGIT0:
Speed = 0;
OffTimer();
break;
case DIGIT1:
StartFan = 1;
Speed = 1;
break;
case DIGIT2:
StartFan = 1;
Speed = 2;
break;
case DIGIT3:
StartFan = 1;
Speed = 3;
break;
case DIGIT4:
StartFan = 1;
Speed = 4;
break;
case DIGIT5:
StartFan = 1;
Speed = 5;
break;
case DIGIT6:
StartFan = 1;
Speed = 6;
break;
case DIGIT7:
StartFan = 1;
Speed = 7;
break;
case DIGIT8:
StartFan = 1;
Speed = 8;
break;
case DIGIT9:
StartFan = 1;
Speed = 9;
break;
case CH_MINUS:
FanOn = 0;
OffTimer();
break;
case CH_PLUS:
if(Speed == 0) Speed++;
StartFan = 1;
break;
case PREV:
if(FanOn) Time--;
SetTimer();
break;
case NEXT:
if(FanOn) Time++;
SetTimer();
break;
case EQ:
OffTimer();
break;
case PLAY:
OnTimer();
break;
default:
UnknownCmd = 1;
break;
}
if(!UnknownCmd){
LEDOn(); // A new command received
ClearLED = 1; // Clear LED after a little time
Ticks = 0; // Reset timer ticks
SetSpeed();
}
}// if((IRData.byte0 ^ IRData.byte1) == 0)
}// if(IRData.byte3 == 0)
}//if((IRData.byte3 ^ IRData.byte2) == 0)
}
/**
Off the timer, without changing previous set time
*/
void OffTimer(void)
{
TimerRunning = 0; // Turn off timer
Time = eeprom_read(1); // Read the eeprom, value
EETimeUpdate = 1; // Update time in the eeprom
EECounter = 0; // Clear the eeprom counter to update eeprom
}
/**
On timer, start with the previous set time, if the timer is not running
*/
void OnTimer(void)
{
if(FanOn == 1) // Only start Timer when fan on
{
if(!TimerRunning) // Nothing to do if already started
{
TimerRunning = 1; // Start the timer
Time = eeprom_read(1); // Get time eeprom
if(Time == 0) // If zero, switch on timer with a non zero value, i.e one hour
Time++;
TimeCounter = TIME_COUNT; // Reload the counter
EETimeUpdate = 1; // Update time in the eeprom
EECounter = 0; // Clear the eeprom counter to update eeprom
}
}
}
/**
Set the counters for the timer. When the counter reached zero, the fan will be turned off
If the timer not running, it reload time value with the last saved value the eeprom,
otherwise adjust counters as required, and clear eeprom counter to update time value in the
eeprom, for the same it set a EETimeUpdate flag
*/
void SetTimer(void)
{
if(Time & 0x80) // A neg, so clear it
Time = 0;
if(Time > 8)
Time = 8; // Max 8 hours
if(FanOn == 0) // Nothing to do if fan is not running
return;
if(!TimerRunning && (Time != 0)) { // If decrementing, and time reached zero, on further
Time = eeprom_read(1); // decrements never start the timer, only start on
TimerRunning = 1; // increments, i.e when time not zero.
if(Time == 0) // If zero, start with a non zero value
Time++; // i.e. set to one
}
if(Time == 0) // Stop timer, if time is zero
TimerRunning = 0;
TimeCounter = TIME_COUNT; //
EETimeUpdate = 1; // Update time in the eeprom
EECounter = 0; // Clear the eeprom counter to update eeprom
}
/**
Set the speed and update phase angle for a given speed. If start fan flag is set, and fan not running
it starts fan will full speed for a second, then changes to ed speed.
*/
void SetSpeed(void)
{
if(Speed & 0x80) // A neg, keep it as zero
Speed = 0;
if(Speed >= 10) // Reach the max.
Speed = 9;
if(Speed == 0){
StartFan = 0; // For a zero speed, switch off
FanOn = 0;
}
if(StartFan){ // If required, try to start the fan
if(!FanOn){ // Already running?
FanOn = 1; // No. Switch on fan
PhaseAngle = STable[9]; // If just swiched on run it on full speed
Delay2s(); // for a short time
}
StartFan = 0; // Clear the flag
}
if(FanOn == 0) OffTimer();
PhaseAngle = STable[Speed]; // Set the phase angle for the speed
EECounter = 0; // Update EEPROM
}
/**
Decode the IR data received in NEC format
*/
void NECDecoder(void)
{
static unsigned int IRBitTime, PrevIRTimer;
#if 0
static unsigned char Port;
if((Port ^ GPIO) & IR_PIN_MASK) // IR line changed
{
*((unsigned char*)&IRTime) = TMR1L; // Copy the current Timer 1 value (LSB)
*((unsigned char*)&IRTime + 1) = TMR1H; // -- do -- (MSB)
Port = GPIO;
IRBitTime = IRTime - PrevIRTimer;
PrevIRTimer = IRTime;
if(IRBitTime & 0x0800)
IRState = IR_IDLE; // Idle for more than 16 ms
IRRx = 0;
#else
if(IRRx)
{
IRBitTime = IRTime - PrevIRTimer;
PrevIRTimer = IRTime;
if(IRBitTime & 0x0800)
IRState = IR_IDLE; // Idle for more than 16 ms
IRRx = 0;
#endif
Error = 0;
switch(IRState)
{
case IR_IDLE:
if(IsIRDataBitHigh()) // If it is a one, IR starting
IRState++; // Now is IR_MARK
IRDataCount = 0;
IRData._dword = 0;
break;
case IR_MARK: // Now IR Mark just over
if(IRBitTime < IR_MARK_MIN_TIME)
{
Error = 1; // Less than specified mark time
}
IRState++;
break;
case IR_SPACE: // Now IR space just over
if(IRBitTime < IR_SPACE_MIN_TIME)
{
Error = 1; // Less than specified space time
}
if(IRBitTime < IR_SPACE_MIN_TIME * 2)
{
IRState = IR_REPEAT; // If it is less than 4.5 ms, it may be a repeat command
break;
}
IRState++; // Space is 4.5 ms, now IR high
break;
case IR_HIGH: // IR high just over, check it
if(((unsigned char) IRBitTime < MIN_IR_BIT_TIME) || ((unsigned char) IRBitTime > MAX_IR_BIT_TIME))
{
Error = 1; // Too short or too long pulse
}
IRState++;
break;
case IR_LOW: // IR low just over, check it
if(((unsigned char) IRBitTime < MIN_IR_BIT_TIME) || ((unsigned char) IRBitTime > MAX_IR_BIT_TIME * 3))
{
Error = 1; // Too short or too long pulse
}
if((unsigned char) IRBitTime >= MIN_IR_BIT_TIME * 3)
{
AddOneToIRData(); // Longer low time, add a one
}
else
{
AddZeroToIRData(); // Short low time add a zero
}
IRDataCount++; // Increment the counter
IRState--; // Now is IR High
break;
case IR_REPEAT: // In repeat, the 560us IR burst just over, check it now
if(((unsigned char) IRBitTime < MIN_IR_BIT_TIME) || ((unsigned char) IRBitTime > MAX_IR_BIT_TIME))
{
IRCmdRepeat = 0;
Error = 1;
}
IRCmdRepeat = 1;
IRState = IR_IDLE;
break;
}// switch(IRState)
if(Error)
{
InitIR();
}
if(IRDataCount == 32)
{
IRNewHit = 1;
IRState = IR_IDLE;
IRDataCount = 0;
//IROff = 0;
}
IR05Seconds = 0;
}// if(IRRx)
}
/**
Initialise IR states
*/
void InitIR( void ) // initial IR engine
{
IRState = IR_IDLE;
IRNewHit = 0;
IRCmdRepeat = 0;
IRDataCount = 0;
}
/**
Read variables eeprom
*/
void GetEEVariables(void)
{
Speed = eeprom_read(0);
Time = eeprom_read(1);
Status._byte = eeprom_read(2);
}
/**
Write to eeprom, the variables
*/
void SetEEVariables(void)
{
// Compare with the eeprom variables and update if necessory
if(Speed != eeprom_read(0))
eeprom_write(0, Speed);
if(EETimeUpdate) // Time may change while running, so only update
{ // if user make changes
if(Time != eeprom_read(1))
eeprom_write(1, Time);
EETimeUpdate = 0;
}
if(Status._byte != eeprom_read(2))
eeprom_write(2, Status._byte);
}
/**
Create a 2 seconds delay, used to start the fan
*/
void Delay2s(void)
{
unsigned char Count;
Count = 200; // Make a 200 x 10 ms delay
while(--Count != 0)
__delay_ms(10);
}
/**
Delay after a key press. This function retuns after a specified time or when no key pressed down
*/
void KeyDelay(void)
{
unsigned char ms;
ms = 250; // 500 ms delay
do
{
if(!ANY_KEY) // If key released, return
break;
__delay_ms(2);
}while(--ms != 0);
}
void interrupt isr(void)
{
static unsigned char PortStatus, PortChanges;
if(GPIF)
{
PortChanges = PortStatus; // Copy the previous value
PortStatus = GPIO; // Update PortStatus
GPIF = 0; // Clear interrrupt
PortChanges ^= PortStatus; // Find the differences
if(PortChanges & ZC_PIN_MASK) // Zero cross
{
TMR0 = PhaseAngle; // Phase angle is controlled via TMR0, on interrupt it trigger
if(FanOn && (PhaseAngle >= STable[9])){ // For full speed hold trigger now, and TMR0 interrupt (delayed
TriacOn(); // to reach TRIAC holding current) clear the trigger
}
Ticks++; // Ticks @ 10 ms
{
#asm
INCFSZ _KeyCount,W // Inc Key Count, but not beyond 255
MOVWF _KeyCount
CLRW // Clear W
BTFSS SW_UP // Up Key pressed?
MOVLW 0x81 // Y. Load W with 0x81
BTFSS SW_DN // Down Key pressed?
MOVLW 0x82 // Y. Load W with 0x82
MOVWF _Key // Save W to Key
BTFSS _Key,7 // Has any key pressed?
CLRF _KeyCount // N. Clear the counter
#endasm
}
}//if(PortChanges & ZC_PIN_MASK)
if(PortChanges & IR_PIN_MASK) // IR line changed
{
*((unsigned char*)&IRTime) = TMR1L; // Copy the current Timer 1 value (LSB)
*((unsigned char*)&IRTime + 1) = TMR1H; // -- do -- (MSB)
IRRx = 1;
}
}
if(T0IF) // Interrupt depends on phase angle (TMR0 is set by phase angle)
{
if(FanOn){
TriacOn(); // Triac triggered
}
T0IF = 0; // Clear flag
NOP();
NOP();
NOP();
NOP();
TriacOff(); // Triac off, beacuse already triggered
}//if(T0IF)
if(TMR1IF) // @ 524ms; This interrupt is not set, but polled
{ // with other interrupts
TMR1IF = 0;
#ifdef TIMER_ENABLE
if(TimerRunning && (--TimeCounter == 0)) // If timer running, decrement counter
{
TimeCounter = TIME_COUNT; // Reload counter
if(--Time == 0) // The time expired, switch off fan and counter
{
OffTimer(); // Switch off timer
FanOn = 0;
}
}
#endif
{
#asm
INCFSZ _EECounter,W // Inc eeprom timer, but not beyond 255
MOVWF _EECounter
#endasm
}
if(EECounter == 8) // After 4 seconds since clearing the counter
EEPromWrite = 1; // set eeprom write flag
if(IR05Seconds) // After 0.5 seconds of inactivity
IRCmdRepeat = 0; // clear the repeat command
IR05Seconds = 1;
}//if(TMR1IF)
}
what will change in codes:
Sziasztok!
A segítségeteket szeretném kérni. Van egy low pin count boardom és abba tettem egy 16F1823-at. Egy éve még teljesen jól tudtam programozni a rendszert, de most újra elővettem és bármit csinálok (pl. üres főciklus, üres timer1), a beírás után a négy LED-ből (RC0-RC3) az RC0-ra és az RC2-re kötött LEDek felgyulladnak és úgy is maradnak, a másik kettő nem ég (ez a helyes állapot). Ha bármilyen programot égetek be, ugyanezt tapasztalom. Természetesen a regisztereket megfelelően beállítom és törlöm (régebben nem volt a programmal semmi gond, csak a teszt miatt töröltem ki a végrehajtó részeket). Egy másik 1823-at beletettem, ugyanazt az eredményt kaptam. A belső RC oszcillátor frekvenciája 4 MHz.
MPLAB X IDE V6-ot használok, de az 5.4-el is ugyanez volt. Az MPLAB nem ír hibát, minden rendben lezajlik. A használt számítógép is ugyanaz. Az égető egy PICKIT3.
Mivel tesztelhetném, hogy hol lehet a gond?
Nos kipróbáltam ...
A timer1 indítása (setup_timer_) után kell átállítani az RD16 bitet a T1CON regiszterben és azután már működik a timer1L és timer1H regiszter irkafirkálása a régi módon.
Sajna ezt minden timer1 indítás után el kell játszani...
A buffer regiszter nem elérhető közvetlenül a felhasználó számára, ezért ilyenkor csak a set_timer(xx) utasítás marad a "H" regiszterbe íráshoz - ez egyszerre írja az "L" és a "H" regisztert is.
Sajna ez nekem nem jó, mert már valamennyi érték beleketyeg az "L" regiszterbe amikor nekem írni kell/vagy nem a "H" regisztert.
Tehát marad az indításonkénti átállítási procedúra ...
Köszönöm az infókat .. a segítségetek megoldotta a problémát.
A 8 bites PIC-ek timer-ének 16 bites mód haszálatakor a felső byte történő írása két részletben történik meg. A pdf 19.6 timer1 16-Bit Read/Write Mode (és a Figure 19-3. timer1 16-Bit Read/Write Mode Block Diagram ábra) leírja, ill. szemlélteti ezt. Az MSB ténylegesen csak akkor íródik be, ha utána az LSB-t is írod.
|
|