Mikrodenetleyicilerin programlanma sırası avr. avr mikrodenetleyici programlama

İyi günler sevgili radyo amatörleri!
"" sitesine hoş geldiniz

Mikrodenetleyici nedir ve neden gereklidir? Tanımına bakalım:

- elektronik cihazları kontrol etmek için tasarlanmış bir mikro devre veya başka bir şekilde - basit görevleri yerine getirebilen basit bir bilgisayar (mikro bilgisayar).

Yani aslında bir mikrodenetleyici fikirlerimizi (çılgın olanları bile) gerçekleştirmemize izin veren bir cihazdır, ancak elbette yetenekleri dahilinde. Ve en önemlisi, bir fikrin gerçekleştirilmesi, karmaşık elektronik yapıların yaratılmasıyla değil, yalnızca temel olarak düşüncemizin gücüyle sağlanır (bir sihirbaz olmak ister misiniz?).
Radyo amatörleri arasında en popüler olanı iki tür mikrodenetleyicidir:
resim- Mikroçip Teknolojisi
AVR- Atmel tarafından

Kısa bir ara vermek ve konumlarımdan birini netleştirmek istiyorum. Şu veya bu tür mikrodenetleyicilerin, şu veya bu yazılımın ve genel olarak mikrodenetleyicilerle ilgili her şeyin yararlarını, bir şeyler tavsiye etmek ve hatta okuyuculara empoze etmek için tartışmayacağım. Hepsi bir zevk meselesi, kişisel tercih ve mikrodenetleyicileri öğrenmedeki nihai hedefleriniz. Pekala, “uçsuz bucaksız” olduğu için, daha sonraki tüm anlatımımı AVR mikrodenetleyicileri ve çok yaygın olmasa da favorim olan “Algoritma Oluşturucu” programı ile ilgili yapacağım. Farklı mikrodenetleyici türleri, programlar elbette farklılıklara sahiptir, ancak aynı zamanda çok ortak noktaları vardır. Ve mikrodenetleyiciler dünyasını öyle bir şekilde öğreneceğiz ki daha sonra edinilen bilgiler PIC'lere ve herhangi bir yazılıma sorunsuzca uygulanabilecek. Ve bir kez daha hatırlatmama izin verin, bu yazı dizisi, mikrodenetleyicilerin varlığını ilk kez duyanlara ve onlarla nasıl çalışılacağını anlamak isteyenlere yardımcı olma girişimimdir.

Mikrodenetleyicilerle çalışmayı öğrenmek için neye ihtiyacınız var? Bence ana koşullardan birkaçını seçerdim:
1. Arzu ve azim .
Burada her şey çok basit: bir arzu var - her şey yoluna girecek. Ve azimli arzu, genel olarak süper bir şeydir.
2. Mikrodenetleyici cihaz bilgisi.
Derin bilgi burada önemli değildir (ve belki de hiç gerekli değildir), ancak mikrodenetleyicide “gemide” ne olduğunu bilmek gereklidir. Sadece mikrodenetleyicinin nelerden oluştuğunu, hangi cihazlara sahip olduğunu, yeteneklerini, nasıl çalıştığını bilerek - ancak o zaman mikrodenetleyicinin yeteneklerini sonuna kadar kullanabiliriz.
3. Programlama dili ve mikrodenetleyici kontrol komutları bilgisi.
Mikrodenetleyicinin nasıl çalışacağı, ona hangi görevleri atadığınız ve bunları nasıl gerçekleştireceği, içine yerleştirilmiş program tarafından belirlenir - mikrodenetleyici için kendiniz oluşturduğunuz program. Ve gelecekte ortaya çıkabilecek sorunları ele almak için bu nokta üzerinde daha ayrıntılı olarak duracağız.

programı(çeviride, bu kelime “reçete” anlamına gelir) - yaklaşan olayların veya eylemlerin ön açıklaması.

Örneğin, mikrodenetleyicinin bir LED'i yanıp sönmesini istiyoruz. Basit bir görev, ancak yine de, mikrodenetleyicinin bu görevi tamamlaması için, önce adım adım mikrodenetleyicinin tüm eylemlerini tanımlamalı, ihtiyacımız olan sonucu elde etmek için yürütmesi gereken bir program yazmalıyız - yanıp sönen bir LED . Bunun gibi bir şey:
♦ LED'i yak:
- LED'in bağlı olduğu çıkışı bilgi çıkışı üzerinde çalışacak şekilde yapılandırın
- bu pime, LED'i yakmanıza izin verecek bir mantık seviyesi uygulayın
♦ Bir süre bekleyin:
- duraklama oluşturan alt programa gidin ("çiğnenmesi" de gerekir)
- duraklatma alt programı tamamlandıktan sonra ana programa dönün
♦ LED'i kapatın:
- LED'i söndürerek çıkışa bir mantık seviyesi uygulayın
ve benzeri.
terim ile programı başka bir terim ayrılmaz bir şekilde bağlantılıdır - algoritma(Kurt ve Tavşan, Tom ve Jerry gibi).

algoritma- istenen sonuca ulaşmak için prosedürü açıklayan bir dizi talimat.

Programda ise en detaylı şekildeyiz eylemleri reçete mikrodenetleyici, sonra algoritmada biz eylemin seyrini belirlemek mikrodenetleyici, buna dayanarak bir program oluşturacağız. Yukarıdaki örneğe benzer:
♦ LED'i yak
♦ Bir süre bekleyin
♦ LED'i kapatın
ve benzeri.
Böylece, algoritma programın öncüsüdür. Ve bir algoritma ne kadar dikkatli ve düşünceli bir şekilde oluşturulursa, bir program oluşturmak o kadar kolay olacaktır.

Toplamda, mikrodenetleyici programı, hedeflerimize ulaşmak için yürütmesi gereken bir dizi komut ve talimat biçiminde mikro denetleyicinin bir dizi eylemidir.

Mikrodenetleyici komutları bir ve sıfır kümesi gibi görünür:
00110101 011000100
Lafta - komut kodları, ve komut kodları, mikrodenetleyicinin anladığı dildir. Ve algoritmamızı Rusça'dan mikrodenetleyicinin diline çevirmek için - bu sıfırlar ve birler kümelerine özel programlar var.
Bu programlar, mikrodenetleyicinin çalışma sırasını bizim için az çok anlaşılabilir bir dilde tanımlamamıza ve daha sonra bu sırayı mikrodenetleyicinin anlayabileceği bir dile çevirmemize izin verir. makine kodu- sadece mikrodenetleyicinin anladığı bir dizi komut ve talimat (sıfırlar ve birler). Bir programcı tarafından yazılmış bir programın metnine denir. kaynak kodu. Program, programlama dilinden (kaynak kodu) mikrodenetleyici diline (makine kodu) çevrilir. çevirmenler. Çevirmen program metnini makine kodlarına dönüştürür ve bunlar daha sonra mikrodenetleyicinin belleğine yazılır.
Bu tür programlarda, mikrodenetleyicinin çalışma sırası özel bir dil olan programlama dili ile tanımlanır. Programlama dili bizim insan dilimizden farklıdır. İletişim dilimiz öncelikle bilgi alışverişi içinse, o zaman:

Programlama dili - bu, komutları, talimatları, mikrodenetleyici için net bir eylem kılavuzu iletmenin bir yoludur.

Birçok programlama dili vardır ve bunlar iki türe ayrılabilir:
düşük seviyeli programlama dilleri
üst düzey programlama dilleri
Fark ne. Ve mikrodenetleyiciye yakınlıkları bakımından farklılık gösterirler.
Mikroişlemci teknolojisinin ortaya çıkışının başlangıcında, programlar makine kodlarında yazılmıştır, yani tüm çalışma algoritması sırayla sıfırlar ve birler şeklinde yazılmıştır. Program şöyle görünüyordu:

01000110
10010011
01010010

Herhangi birinin böyle bir iki sayı kombinasyonunu çözebilmesi olası değildir ve ilk programcıların çalışmaları çok zahmetli olmuştur. Hayatlarını kolaylaştırmak için programcılar ilk programlama dillerini yaratmaya başladılar. Dolayısıyla, programlama dili böyle bir sıfır ve birler kümesine ne kadar yakınsa, o kadar "düşük seviye" ve onlardan ne kadar uzak olursa "yüksek seviye" o kadar yüksek olur.
Mikrodenetleyiciler için en yaygın programlama dilleri:
- düşük seviyeli dil - montajcı
– üst düzey dil – C (Ci)
Aralarındaki farkın bir örneğine bakalım (bu örnekler soyuttur).
Diyelim ki iki sayı eklememiz gerekiyor: 25 ve 35.
Yerel kodda bu komut şöyle görünebilir:
00000101 1101001
Düşük seviyeli dilde:
EKLE Rd, Rr
Üst düzey dilde:
25+35
Düşük seviyeli ve yüksek seviyeli diller arasındaki fark çıplak gözle görülebilir, dedikleri gibi yorumlar gereksizdir.
Ama bu örnekleri daha derine inelim. Montajcıdaki örnekle aynı olduğu için makine kodu örneğini analiz etmeyeceğiz. Özünde, Montaj talimatları, sıfırlar ve birler arasında kaybolmamak için basitçe harf kısaltmalarına atanan aynı makine kodlarıdır (komutlar). Montajcı talimatı ADD Rd, Rr ile mikrodenetleyiciyi bulunan iki sayıyı toplamaya ayarladık (ve bunun için önce onları oraya yazmalıyız) - ilki Rd'ye, ikincisi Rr'ye ve toplamanın sonucunu yerleştiriyoruz Rd. Gördüğünüz gibi, mikrodenetleyici için çok özel bir görev belirledik: nereden alınır, onunla ne yapılır ve sonucu nereye koyarız. Bu durumda doğrudan mikrodenetleyici ile çalışıyoruz.
Üst düzey dilde komut: 25+35 , bize tanıdık gelen, gözümüze hoş gelen bir matematiksel gösterim. Ancak bu durumda, doğrudan mikrodenetleyici ile çalışmıyoruz, sadece iki sayı ekleme görevini belirledik. Bu durumda sonuç ve eylemlerin sırası, montajcı komutunu yürütürken olduğu gibi olacaktır: önce bu iki sayı bir yere yazılacak, sonra toplanacak ve sonuç bir yere yerleştirilecektir.
Ve yüksek seviyeli ve düşük seviyeli diller arasındaki temel fark burada yatmaktadır. Assembler'da tüm süreci kontrol edersek (beğensek de beğenmesek de): bu iki sayının nerede yazıldığını ve sonucun nerede olacağını biliyoruz, o zaman yüksek seviyeli bir dilde süreci kontrol etmiyoruz. Program, sayıların önceden nereye yazılacağına ve sonucun nereye yerleştirileceğine kendisi karar verir. Çoğu durumda bunu bilmemize gerek yoktur, çünkü bizim için asıl sonuç çıktıdaki 60 sayısıdır. Sonuç olarak, yüksek seviyeli dillerdeki programlar daha okunaklı, göze hoş gelen ve daha küçük boyutlu - sonuçta, “tüm deliklere tırmanmak” ve mikrodenetleyicinin her adımını boyamak zorunda değiliz, program bunu daha sonra derlerken bizim için yapar - makine kodlarına çevirir . Ama bir dezavantajı da var. Assembler'da ve C'de yazılan iki özdeş algoritma, bunları makine kodlarına dönüştürdükten sonra farklı bir boyuta sahip olacaktır: Assembler'da yazılan bir program, C'de yazılan bir programdan %20-40 daha kısa olacaktır - şeytan bilir C'nin hangi yöne gittiğini ihtiyacımız olan sonuca ulaşmak. Ve yüksek seviyeli bir dilde güvenin olmadığı ve bir C programında Assembler'da yazılmış kodu ekledikleri durumlar vardır.
Profesyonel programcılar, kural olarak, birkaç programlama dilini bilir (veya farklı dillerde uzmanları içeren bir ekipte çalışır), özelliklerini ve faydalarını tek bir programda yaratıcı bir şekilde birleştirir. Eh, biz amatörler, en az bir dil bilmemiz gerekiyor (yeni başlayanlar için) ve düşük seviyeli bir dilden başlamalıyız (ve buna kesinlikle inanıyorum ve kimse beni ikna etmeyecek) - Assembly.

Bence ve burada her şey bizim için açık - bir programlama dilini farklı bir şekilde öğrenmeniz gerekiyor - hiçbir şekilde.

Mikrodenetleyiciyi kontrol etmek için komutlar ve talimatlar.
AVR mikrodenetleyicileri, içerdiği tüm olasılıkları gerçekleştirmesine izin veren 130'dan fazla farklı komuta sahiptir. Ama hemen söyleyeyim ki, bırakın hepsini kullanmak şöyle dursun, çok az amatör hepsini bilir. Genellikle amatör antrenmanlarda takımların yarısı, hatta daha azı yeterli bilgi birikimine sahiptir. Ama komutları öğrenmen gerekiyor. Ne kadar çok komut bilirseniz, o kadar karmaşık (kelimenin tam anlamıyla) ve daha zarif programlar olacaktır.

Aritmetik mantık birimi ve bellek organizasyonu - program belleği, veri belleği, kalıcı bellek



avr ile ilgili bu eğitimde, yeni başlayanlar için mikrodenetleyicileri programlamak için en temel şeyleri açıklamaya çalıştım. ortalama. Tüm örnekler bir mikrodenetleyici üzerine inşa edilmiştir atmega8. Bu, tüm dersleri tekrarlamak için yalnızca bir MK'ye ihtiyacınız olacağı anlamına gelir. Elektronik devre emülatörü olarak Proteus kullanılıyor - bence yeni başlayanlar için en iyi seçenek. Tüm örneklerdeki programlar, avr CodeVision AVR için C derleyicisine yazılmıştır. Neden bazı montajcıda değil? Çünkü yeni başlayanlar zaten bilgi yüklüdür ve iki sayıyı çarpan program, assembler'da yaklaşık yüz satır alır ve karmaşık cesur projelerde C kullanırlar.CodeVision AVR derleyicisi atmel mikrodenetleyicileri için keskinleştirilmiştir, uygun bir kod üretecine, bir iyi bir arayüz ve doğrudan ondan mikrodenetleyici tarafından yanıp sönebilir.

Bu eğitici, aşağıdakilerin nasıl yapılacağını basit örneklerle gösterecek ve açıklayacaktır:

  • Mikrodenetleyicileri programlamaya başlayın, nereden başlamalı, bunun için neye ihtiyacınız var.
  • avr için bellenim yazmak, bir bilgisayarda kod simüle etmek ve hata ayıklamak için hangi programları kullanmalı,
  • MK'nin içinde hangi çevresel aygıtlar var, programınızı kullanarak bunları nasıl kontrol edebilirsiniz?
  • Bitmiş ürün yazılımı mikrodenetleyiciye nasıl yazılır ve nasıl hata ayıklanır
  • Cihazınız için bir PCB nasıl yapılır
MK programlamaya ilk adımları atmak için sadece iki programa ihtiyacınız var:
  • Proteus bir emülatör programıdır (gerçek lehimlemeye başvurmadan içinde bir devre geliştirebilir ve ardından programımızı bu devre üzerinde test edebilirsiniz). İlk önce tüm projeleri Proteus'ta başlatacağız ve sonra zaten gerçek bir cihazı lehimleyebiliriz.
  • CodeVisionAVR, AVR için bir C programlama dili derleyicisidir. İçinde mikrodenetleyici için programlar geliştireceğiz ve gerçek bir MK'yi doğrudan ondan flaş etmek mümkün olacak.
Proteus'u kurduktan sonra çalıştırın
Bize eşlik eden projeleri görmemizi teklif ediyor, kibarca reddediyoruz. Şimdi bunun içindeki en basit devreyi oluşturalım. Bunu yapmak için simgeye tıklayın görsel olarak hiçbir şey olmuyor. Şimdi küçük harfe tıklamanız gerekiyor R (kütüphaneden seçin) bileşen listesi panelinde bileşen seçim penceresi açılacaktır.
maske alanına kütüphanede bulmak istediğimiz bileşenin adını girin. Örneğin, bir mega8 mikrodenetleyici eklememiz gerekiyor
sonuç listesinde, mega8'i dürtün ve düğmeye basın TAMAM. Bileşenler listesinde bir mega8 mikrodenetleyicimiz var
Böylece maske alanına word'ü girerek bileşen listesine bir direnç daha ekliyoruz. res ve LED neden olmuş

Parçaları diyagrama yerleştirmek için parçaya tıklayın, ardından diyagram alanına tıklayın, bileşenin konumunu seçin ve tekrar tıklayın. Soldaki devreye toprak veya ortak eksi eklemek için "Terminal"e tıklayın ve Toprak'ı seçin. Böylece tüm bileşenleri toplayıp bunları birbirine bağlayarak çok basit bir devre elde ederiz.
Her şey, şimdi ilk planımız hazır! Ama o ne yapabilir diye soruyor olabilirsiniz. Ama hiçbir şey. Hiçbir şey, çünkü mikrodenetleyicinin çalışması için onun için bir program yazmanız gerekiyor. Program, mikrodenetleyicinin yürüteceği talimatların bir listesidir. Bir bacağa takmak için mikrodenetleyiciye ihtiyacımız var PC0 mantık 0 (0 volt) ve mantık 1 (5 volt).

Mikrodenetleyici için Program Yazma

CodeVisionAVR derleyicisini kullanarak programı C dilinde yazacağız. CV'yi başlattıktan sonra bize ne yaratmak istediğimizi soruyor: Kaynak veya Proje İkincisini seçip OK düğmesine basıyoruz. Ardından, CVAVR CodeWizard'ı çalıştırmamız istenecek (bu, yeni başlayanlar için paha biçilmez bir araçtır, çünkü programın ana iskeletini oluşturabilir) Seç Evet
Sihirbaz Chip sekmesi etkinken başlar, burada MK'mizin modelini seçebiliriz - bu mega8 ve MK'nin çalışacağı frekans (mega8 varsayılan olarak 1 megahertz'e ayarlanmıştır), bu yüzden her şeyi gösterildiği gibi ayarladık yukarıdaki ekran görüntüsü. Bağlantı Noktaları sekmesine gidin
atmega8 mikrodenetleyicinin 3 portu vardır: Port C, Port D, Port B. Her portun 8 pini vardır. Bağlantı noktası pimleri iki durumda olabilir:
  • çıkış
DDRx.y yazmacı yardımıyla pini giriş veya çıkış olarak ayarlayabiliriz. eğer
  • DDRx.y = 0 - çıktı şu şekilde çalışır GİRİŞ
  • DDRx.y = 1 pin çalışıyor ÇIKIŞ
Pin çıkış olarak konfigüre edildiğinde lojik 1 (+5 volt) ve lojik 0 (0 volt) olarak ayarlayabiliriz. Bu, PORTx.y kaydına yazılarak yapılır. Daha sonra giriş-çıkış portları hakkında detaylı olarak tartışılacaktır. Ve şimdi her şeyi ekran görüntüsünde gösterildiği gibi ayarlıyoruz ve Dosya->Oluştur, Kaydet ve Çık'ı tıklayın. Daha sonra CodeWizard bize projeyi kaydetmemizi önerecek, biz onu kaydedip koda bakacağız:

#Dahil etmek //zaman gecikmeleri oluşturma kitaplığı void main(void) ( PORTB=0x00; DDRB=0x00; PORTC=0x00; DDRC=0x01; // PC0 bacak çıkışını PORTD=0x00; DDRD=0x00; // Zamanlayıcı/Sayaç 0 başlatma TCCR0=0x00; TCNT0=0x00; // Zamanlayıcı/Sayaç 1 başlatma TCCR1A=0x00; TCCR1B=0x00; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00=000; OCR1 ; OCR1BL=0x00; // Zamanlayıcı/Sayaç 2 başlatma ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00; // Harici Kesinti(ler) başlatma MCUCR=0x00; // Zamanlayıcı(lar)/Sayaç(lar) ) Kesinti(ler) başlatma TIMSK=0x00; // Analog Karşılaştırıcı başlatma ACSR=0x80; SFIOR=0x00; while (1) ( ); )


Buradaki her şey size korkutucu ve tanıdık gelmeyebilir, ancak gerçekte her şey öyle değil. Kullanmadığımız MK çevre birimlerinin başlatılması atılarak kod basitleştirilebilir. Sadeleştirmeden sonra şöyle görünür:

#Dahil etmek //mikrodenetleyici mega8 ile çalışmak için kütüphane #include //zaman gecikmeleri oluşturmak için kitaplık void main(void) ( DDRC=0x01; /* PC0 ayağını yap 0x01 çıktı girişi size yabancı gelebilir ve bu sadece onaltılık olarak 1 rakamıdır, bu satır 0b00000001'e eşdeğer olacaktır binary'de tam olarak böyle yazacağım. */ while (1) ( ); )


Herşey yolunda. Fakat LED'in yanıp sönmesi için PC0 bacağındaki mantık seviyesini değiştirmemiz gerekiyor. Bunu yapmak için ana döngüye birkaç satır ekleyin:

#Dahil etmek //mikrodenetleyici mega8 ile çalışmak için kütüphane #include //zaman gecikmeleri oluşturmak için kitaplık void main(void) ( DDRC=0x01; /* PC0 ayağını yap 0x01 çıktı girişi size yabancı gelebilir ve bu sadece onaltılık olarak 1 rakamıdır, bu satır 0b00000001'e eşdeğer olacaktır binary'de ise tam olarak şöyle yazacağım.*/ while (1)//ana program döngüsü (// ana program döngüsünün operatör braketi PORTC.0=1; // port C 1'i pin olarak ayarla 0 delay_ms(500); //500 milisaniyede bir gecikme yap PORTC.0=0; // C 0 portunu pin 0'a ayarla delay_ms(500); // 500 milisaniyelik bir gecikme yap );// operatör braketini kapat ana program döngüsünün)


Her şey, şimdi kod hazır. Programımızı derlemek (MK işlemci talimatlarına çevirmek) için Build all Project files ikonuna tıklıyoruz. Projemizde bulunan Exe klasöründe hex uzantılı bir dosya görünmelidir, bu bizim MK için ürün yazılımı dosyamızdır. Proteus içerisinde bulunan sanal mikrodenetleyiciye ürün yazılımımızı beslemek için Proteus içerisinde bulunan mikrodenetleyicinin görüntüsüne çift tıklamanız gerekmektedir. Böyle bir pencere çıkacak
Program Dosyası alanındaki klasör simgesine tıklayın, hex - bellenimimizin dosyasını seçin ve OK düğmesine basın. Artık devremizin simülasyonunu çalıştırabiliriz. Bunu yapmak için Proteus penceresinin sol alt köşesindeki "Oynat" düğmesine tıklayın.

MK çalışmasının montajcı ile başlaması gerektiğini bir veya iki defadan fazla söyledim. Sitedeki bütün bir kurs buna ayrıldı (çok tutarlı olmasa da, yavaş yavaş onu yeterli bir görünüme kavuşturuyorum). Evet zor, sonuç ilk gün olmayacak ama kumandanızda neler olduğunu anlamayı öğreneceksiniz. Nasıl çalıştığını bileceksiniz ve bir maymun gibi diğer insanların kaynaklarını kopyalamayacaksınız ve neden aniden çalışmayı bıraktığını anlamaya çalışacaksınız. Ayrıca, C'nin en uygunsuz anda bir dirgen ile çıkacak cahil kod ile uğraşması çok daha kolaydır.

Ne yazık ki, herkes hemen sonuç istiyor. Bu nedenle, diğer yoldan gitmeye karar verdim - C hakkında bir eğitim yapmak için, ancak iç çamaşırını göstererek. İyi bir gömücü programcı, demir parçasını her zaman greave tarafından sıkıca tutar ve izinsiz tek bir adım atmasını engeller. Peki önce C kodu ne olacak, sonra derleyici neyi doğurdu ve gerçekte nasıl çalışıyor :)

Öte yandan, C'nin güçlü noktası kod taşınabilirliğidir. Tabii ki, her şeyi doğru yazmak için. İş algoritmalarını ve bunların demir uygulamalarını projenin farklı bölümlerine ayırmak. Daha sonra algoritmayı başka bir MK'ye aktarmak için sadece donanıma tüm erişimin yazıldığı arayüz katmanını yeniden yazmak ve tüm çalışma kodunu olduğu gibi bırakmak yeterli olacaktır. Ve elbette, okunabilirlik. Sish kaynak kodunu bir bakışta anlamak daha kolaydır (her ne kadar .. örneğin, neye dokunacağım umurumda değil - en azından si, en azından asm :)), ama yine de, her şey doğru yazılmışsa. Bu noktalara da dikkat edeceğim.

Tüm örneklerin aslan payının yerleştirileceği deneysel bir demir parçası olarak hata ayıklama panom olacaktır.

AVR için ilk C programı

Derleyici Seçme ve Ortam Kurma
AVR için birçok farklı C derleyicisi vardır:
Öncelikle bu IAR AVR C- neredeyse kesin olarak AVR için en iyi derleyici olarak kabul edildi, tk. denetleyicinin kendisi, Atmel ve IAR uzmanları arasında yakın işbirliği içinde oluşturuldu. Ama her şey için ödemek zorundasın. Ve bu derleyici sadece pahalı ticari bir yazılım değil, aynı zamanda o kadar çok ayara sahip ki, onu derlemek için çok çalışmanız gerekiyor. Onunla gerçekten bir arkadaşlığım yoktu, bağlantı aşamasındaki garip hatalar nedeniyle proje çürüdü (daha sonra bunun çarpık bir çatlak olduğunu öğrendim).

ikinci gider WinAVR GCC güçlü bir optimize edici derleyicidir. Tam açık kaynak, çapraz platform, genel olarak hayatın tüm zevkleri. Ayrıca AVR Studio'ya mükemmel bir şekilde entegre olur ve tam orada hata ayıklamanıza izin verir, bu da son derece kullanışlıdır. Genel olarak, onu seçtim.

Ayrıca sahibiz CodeVision AVR Cçok popüler bir derleyicidir. Sadeliği nedeniyle popüler oldu. Birkaç dakika içinde çalışan bir program alabilirsiniz - başlangıç ​​kodu sihirbazı, herhangi bir uart'ı başlatmak için standartları damgalayarak buna büyük ölçüde katkıda bulunur. Dürüst olmak gerekirse, ona bir şekilde şüpheyle yaklaşıyorum - bu derleyici tarafından yazılan bir programı sökmek zorunda kaldığımda, bir tür püresi çıktı ve kod değil. Oldukça fazla miktarda kod ve yavaş performansla sonuçlanan korkunç miktarda gereksiz hareket ve işlem. Ancak, belki de orijinal ürün yazılımı yazarının DNA'sında bir hata vardı. Üstelik para istiyor. IAR kadar değil, ancak fark edilir. Ve demo modunda 2 kb'den fazla kod yazmanıza izin vermez.
Tabii ki bir çatlak var ama çalarsanız, o zaman IAR anlamında bir milyon :)

Ayrıca birde şu var Görüntü El Sanatları AVR C ve mikroC mikroelektronikten. İkisini de kullanmak zorunda kalmadım ama... SWGçok övgü mikro paskal, diyorlar ki, çok uygun bir programlama ortamı ve kütüphaneler. Bence MicroC daha da kötü olmayacak, aynı zamanda ödenecek.

Dediğim gibi ben seçtim WinAVRüç nedenden dolayı: ücretsiz, AVR Studio'ya entegre olur ve tüm durumlar için sadece bir grup hazır kod yazılır.

Öyleyse WinAVR'yi ve AVR Studio ile indirin. Ardından, önce stüdyo kurulur, ardından yukarıdan WinAVR toplanır ve bir eklenti şeklinde stüdyoya yapışır. WinAVR'yi C:\WinAVR gibi kısa bir yola koymanızı şiddetle tavsiye ederim, böylece yollarla ilgili birçok sorundan kaçınacaksınız.

Proje oluşturma
Yani stüdyo kuruldu, C batırıldı, bir şeyler programlamayı denemenin zamanı geldi. En basitinden, en basitinden başlayalım. Stüdyoyu çalıştırın, orada AVR GCC derleyicisi olarak yeni bir proje seçin ve projenin adını girin.

Çalışma alanı boş bir *.c dosyasıyla açılır.

Artık stüdyonun yer imlerindeki yolların görüntüsünü yapılandırmaktan zarar gelmez. Bunu yapmak için şu adrese gidin:
Menü Araçları - Seçenekler - Genel - Dosya Sekmeleri ve açılır listeden "Yalnızca Dosya Adı" seçeneğini seçin. Aksi takdirde çalışmak imkansız olacaktır - sekme dosyanın tam yolunu içerecek ve ekranda iki veya üçten fazla sekme olmayacaktır.

Proje kurulumu
Genel olarak, tüm bağımlılıkların tanımlanacağı bir make dosyası oluşturmak klasik olarak kabul edilir. Ve bu muhtemelen doğru. Ama benim için, tam entegre IDE'lerle büyüyen uVision veya AVR Stüdyosu bu yaklaşım son derece yabancıdır. Bu nedenle, stüdyonun her yolu ile kendi yolumda yapacağım.

Dişli düğmesine tıklayın.


Bunlar, projenizin ayarları veya daha doğrusu make dosyasının otomatik oluşturulması için ayarlardır. İlk sayfada, MK'nizin çalışacağı frekansı girmeniz yeterlidir. Sigorta bitlerine bağlıdır, bu nedenle frekansın 8000000Hz olduğunu varsayıyoruz.
Ayrıca optimizasyon satırına da dikkat edin. Şimdi -Os boyut optimizasyonu var. Şimdilik olduğu gibi bırakın, sonra bu parametre ile oynamayı deneyebilirsiniz. -O0 hiç optimizasyon değil.

Bir sonraki adım yolları ayarlamaktır. Her şeyden önce, projenizin dizinini buraya ekleyin - oraya üçüncü taraf kitaplıkları koyacaksınız. ".\" yolu listede görünecektir

Make dosyası oluşturulur, projenizdeki varsayılan klasörde ona bakabilirsiniz, sadece bir göz atın, orada ne olduğunu görün.


Şimdilik bu kadar. Her yerde Tamam'ı tıklayın ve kaynağa gidin.

Sorunun formülasyonu
Boş bir sayfa, bir diyotun banal yanıp sönmesi artık eklenmediğinden, bir tür kurnaz fikri somutlaştırmak için caziptir. Hemen boğayı boynuzlarından alalım ve bilgisayarla bir bağlantı kuralım - bu yaptığım ilk şey.

Şu şekilde çalışacaktır:
COM portuna bir birim geldiğinde (kod 0x31), diyotu açacağız ve sıfır geldiğinde (kod 0x30) onu söndüreceğiz. Ayrıca, her şey kesintilerde yapılacak ve arka plan görevi başka bir diyotun yanıp sönmesi olacaktır. Basit ve anlamlı.

şemanın montajı
USB-USART dönüştürücü modülünü mikrodenetleyicinin USART pinlerine bağlamamız gerekiyor. Bunu yapmak için, iki telden bir jumper alıyoruz ve bunları çapraz olarak pimlere yerleştiriyoruz. Yani, denetleyicinin Rx'ini dönüştürücünün Tx'ine ve dönüştürücünün Tx'ini denetleyicinin Rx'ine bağlarız.

Görünüşe göre, sonunda, bu şema:


Kalan çıkışları bağlamayı düşünmüyorum, güç kaynağı, reset standarttır

kodu yazıyoruz

Hemen bir rezervasyon yapacağım, özellikle C dilinin tanımına girmeyeceğim. Bunu yapmak için, klasik "C Programlama Dili"nden K&R'ye ve çeşitli kılavuzlara kadar muazzam miktarda malzeme var.

Depomda böyle bir yöntem bulundu, bir keresinde bu dili kullanarak çalıştım. Her şey kısa, net ve öz. Yavaş yavaş yazıp siteme sürüklüyorum.

Tüm bölümlerin henüz oraya taşınmadığı doğru, ama bence çok uzun sürmedi.

Bunu daha iyi tanımlamam pek olası değil, bu nedenle, eğitim kursundan, Cish'in karmaşıklıklarının ayrıntılı bir açıklaması yerine, bu kılavuzun tek tek sayfalarına doğrudan bağlantılar vereceğim.

Kitaplıklar ekleme.
Öncelikle gerekli kütüphaneleri ve başlıkları tanımları ile ekliyoruz. Sonuçta C evrensel bir dildir ve bizim AVR ile çalıştığımızın açıklanması gerekir, bu yüzden kaynak koduna şu satırı girin:

1 #Dahil etmek

#Dahil etmek

Bu dosya klasörde bulunur WinAVR ve denetleyicinin tüm kayıtlarının ve bağlantı noktalarının bir açıklamasını içerir. Ve derleyici tarafından iletilen belirli bir denetleyiciye atıfta bulunarak, orada her şey zor. Yapmak parametredeki dosya MCU ve bu değişkene dayalı olarak, bu belirli denetleyici için tüm bağlantı noktalarının ve kayıtların adreslerinin açıklamasını içeren bir başlık dosyası projenize bağlanır. Nasıl! Onsuz, siz de yapabilirsiniz, ancak o zaman SREG veya UDR gibi sembolik kayıt adlarını kullanamayacaksınız ve her birinin adresini "0xC1" gibi hatırlamanız gerekecek ve bu kafanızı kırıyor.

Aynı takım #Dahil etmek<имя файла> herhangi bir metin dosyasının içeriğini projenize eklemenize olanak tanır, örneğin işlevlerin açıklamasını içeren bir dosya veya başka bir kod parçası. Direktifin bu dosyayı bulabilmesi için projemizin yollarını belirttik (WinAVR dizini varsayılan olarak orada zaten kayıtlıdır).

ana işlev.
Bir C programı tamamen fonksiyonlarla ilgilidir. Herhangi bir sırayla ve birçok farklı şekilde yuvalanabilir ve birbirlerinden çağrılabilirler. Her işlevin üç gerekli parametresi vardır:

  • Dönüş değeri, örneğin, günah(x) x'in sinüsünün değerini döndürür. Kısaca matematikte olduğu gibi.
  • Aktarılan parametreler, aynı x.
  • İşlev gövdesi.

Geçirilen ve döndürülen tüm değerler, verilere bağlı olarak bir tür olmalıdır.

Her C programı bir fonksiyon içermelidir ana ana programa bir giriş noktası olarak, aksi takdirde hiç C değil :). Bir başkasının milyonlarca dosya kaynağında main bulunmasıyla, bunun her şeyin başladığı programın ana kısmı olduğunu anlayabilirsiniz. Burada ayarlayacağız:

1 2 3 4 5 int main(void ) ( 0 döndür; )

int main(void) ( 0 döndür; )

İşte bu, ilk basit program yazıldı, hiçbir şey yapmaması önemli değil, daha yeni başladık.

Bakalım ne yapmışız.
int ana işlevin döndürdüğü veri türüdür.

Tabii ki, mikrodenetleyicide ana prensipte hiçbir şey iade edilemez ve teoride void main(void), ancak GCC orijinal olarak PC'de keskinleştirilmiştir ve orada program tamamlandıktan sonra değeri işletim sistemine döndürebilir. Bu nedenle GCC üzerinde void main(void) Uyarı üzerine yemin eder.

Bu bir hata değil, işe yarayacak ama uyarıları sevmiyorum.

geçersiz bu, işleve aktardığımız veri türüdür, bu durumda ana ayrıca dışarıdan hiçbir şeyi kabul edemez şair geçersiz- boş. Hiçbir şeyin iletilmesi veya döndürülmesi gerekmediğinde bir saplama kullanılır.

işte bunlar { } küme parantezleri bir program bloğudur, bu durumda işlevin gövdesi ana, kod orada bulunacaktır.

dönüş- bu, ana işlevin tamamlandıktan sonra vereceği dönüş değeridir, çünkü bir int'miz, yani bir sayımız var, o zaman bir sayı döndürmeliyiz. Her ne kadar hala mantıklı olmasa da, çünkü. ana mikrodenetleyicide sadece hiçbir yere gidemeyiz. null döndürürüm. Nefig için. Derleyici genellikle akıllıdır ve bu durum için kod üretmez.
Her ne kadar sapıksa, o zaman ana MK'ye gidebilirsiniz - örneğin, önyükleyici bölümüne düşebilir ve yürütebilirsiniz, ancak burada geçiş adreslerini düzeltmek için zaten düşük düzeyde bellenim seçimine ihtiyacınız olacak. Aşağıda bunu nasıl yapacağınızı görecek ve anlayacaksınız. Ne için? Şimdi bu başka bir soru, vakaların% 99,999'unda bu gerekli değil :)

Bitti, devam et. Bir değişken ekleyelim, buna gerçekten ihtiyacımız yok ve değişkenleri onsuz tanıtmamalıyız, ama öğreniyoruz. Fonksiyon gövdesine değişkenler eklenirse, bunlar yereldir ve yalnızca bu fonksiyonda bulunur. Fonksiyondan çıktığınızda bu değişkenler silinir ve RAM bellek daha önemli ihtiyaçlara verilir. .

1 2 3 4 5 6 int main(void ) ( unsigned char i; 0 döndür; )

int main(void) ( imzasız karakter i; 0 döndür; )

imzasız imzasız anlamına gelir. Gerçek şu ki, ikili gösterimde, en önemli bit işarete atanır, yani +127/-128 sayısı bir bayta (char) sığar, ancak işaret atılırsa, 0'dan 0'a sığacaktır. 255. Genellikle işarete gerek yoktur. Böylece imzasız.
i sadece bir değişken adıdır. Daha fazla yok.

Şimdi portları başlatmamız gerekiyor ve UART. Tabii ki, kütüphaneyi alıp bağlayabilir ve bir çeşit UartInit (9600); ama sonra gerçekte ne olduğunu bilemezsin.

Biz bunu yaparız:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int main(void ) ( unsigned char i; #define XTAL 8000000L #define baudrate 9600L #define bauddivider (XTAL/(16*baudrate)-1)#define HI(x) ((x)>>8) #define LO(x) ((x)& 0xFF) UBRRL = LO(bauddivider) ; UBRRH = HI(baud bölücü) ; UCSRA = 0; UCSRB=1<< RXEN| 1 << TXEN| 1 << RXCIE| 0 << TXCIE; UCSRC = 1 << URSEL| 1 << UCSZ0| 1 << UCSZ1; }

int main(void) ( unsigned char i; #define XTAL 8000000L #define baudrate 9600L #define bauddivider (XTAL/(16*baudrate)-1) #define HI(x) ((x)>>8) #define LO( x) ((x)& 0xFF) UBRRL = LO(baud bölücü); UBRRH = HI(baud bölücü); UCSRA = 0; UCSRB = 1<

Korkutucu? Aslında, gerçek kodun yalnızca son beş satırı vardır. Her şey bu #tanımlamak bir önişlemci makro dilidir. Assembler'dakiyle hemen hemen aynı üstler, ancak sözdizimi biraz farklı.

Gerekli katsayıları hesaplamak için rutin işlemlerinizi kolaylaştıracaklar. İlk satırda bunun yerine şunu söylüyoruz: XTAL 8000000'i güvenle değiştirebilirsiniz ve L- tip göstergesi, işlemcinin saat frekansının uzun olduğunu söylüyorlar. Aynı baud hızı- UART üzerinden veri aktarım sıklığı.

baud bölücü zaten daha karmaşık, bunun yerine önceki ikisinden formülle hesaplanan ifade ikame edilecektir.
iyi ve LO ve SELAM bu sonuçtan, düşük ve yüksek baytlar alınacaktır, çünkü belli ki bir bayta sığamaz. AT SELAM x sekiz kez sağa kaydırılır (makronun giriş parametresi), sonuç olarak, ondan yalnızca yüksek bayt kalır. Ve LO 00FF sayısıyla bit düzeyinde AND işlemi yaparız ve sonuç olarak yalnızca düşük baytı bırakırız.

Yani yapılan her şey gibi #tanımlamak güvenle atabilir ve hesap makinesinde gerekli sayıları hesaplayıp hemen UBBRL = .... satırlarına girebilirsiniz. ve UBBRH=…..

Olabilmek. Fakat! Bunu yap KESİNLİKLE İMKANSIZ!

Bu şekilde ve bu şekilde çalışacak, ancak sözde sihirli sayılar- Hiçbir yerden alınan değerler ve neden olduğu belli değil ve birkaç yıl içinde böyle bir proje açarsanız, bu değerlerin ne olduğunu anlamak çok zor olacak. Ve şimdi, hızı veya kuvarsın frekansını değiştirmek istiyorsanız ve her şeyi yeniden hesaplamanız gerekecek ve bu yüzden koddaki birkaç sayıyı değiştirdiniz ve hepsi bu. Genel olarak, kötü bir kodlayıcı olarak görülmek istemiyorsanız, kodu okunması kolay, anlaşılır ve kolayca değiştirilebilir olacak şekilde yapın.

O zaman her şey basit:
Tüm bu "UBRLL ve Co", dünya ile iletişim kuracağımız UART vericisinin konfigürasyon kayıtlarıdır. Ve şimdi onlara gerekli değerleri atadık, onları istenen hıza ve istenen moda ayarladık.

Girişi görüntüle 1<Şu anlama gelir: 1 al ve yerine koy RXEN bir bayt içinde. RXEN bu yazmacın 4. bitidir UCSRB, böyle 1< 00010000, ikili sayıyı oluşturur TXEN 3. bittir ve 1< 00001000 verecek. Tek bir "|" bu bitsel VEYA, yani 00010000 | 00001000 = 00011000. Aynı şekilde, kalan gerekli yapılandırma bitleri de ortak yığına ayarlanır ve eklenir. Sonuç olarak, toplanan numara UCSRB'ye yazılır. USART bölümündeki MK'deki veri sayfasında daha ayrıntılı olarak açıklanmıştır. O yüzden teknik detaylara takılmayın.

Bitti, ne olacağını görme zamanı. Derlemeye tıklayın ve öykünmeyi başlatın (Ctrl+F7).

hata ayıklama
Her türlü ilerleme çubuğu geçti, stüdyo değişti ve ana işlevin girişinin yakınında sarı bir ok belirdi. İşlemcinin şu anda bulunduğu ve simülasyonun duraklatıldığı yer burasıdır.

Gerçek şu ki, başlangıçta aslında UBRRL = LO(bauddivider); satırındaydı. Sonuçta, tanımladığımız şey kod değil, sadece ön hesaplamalar, bu yüzden simülatör biraz sıkıcı. Ama şimdi ilk talimatın yerine getirildiğini ve bir ağaca tırmanırsanız fark etti. G/Ç Görünümü, USART bölümüne gidin ve oradaki UBBRL baytına bakın, orada zaten bir değer olduğunu göreceksiniz! 0x33.

Bir adım daha at. Başka bir kaydın içeriğinin nasıl değişeceğine bakın. Bu yüzden hepsini gözden geçirin, belirtilen tüm bitlerin size söylediğim gibi ayarlandığına ve tüm bayt için aynı anda ayarlandığına dikkat edin. İşler Dönüş'ten öteye gitmeyecek - program bitti.

Açılış
Şimdi simülasyonu sıfırlayın. oraya tıklayın Sıfırla (Üst Karakter+F5). Demonte edilmiş listeyi açın, şimdi kontrol cihazında gerçekte neler olduğunu göreceksiniz. Görünüm -> Parçalayıcı. Ve YYAAAA değil!!! montajcı!!! BERBAT!!! AMA ZORUNDASINIZ. Böylece daha sonra, bir şeyler ters gittiğinde, kodda aptallaşmazsınız ve forumlarda daha fazla soru sormazsınız, ancak hemen sakatatlara girin ve nerede bir fişiniz olduğuna bakın. Orada korkunç bir şey yok.

İlk önce seriden üstler olacak:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 +00000000: 940C002A JMP 0x0000002A Atla +00000002: 940C0034 JMP 0x00000034 Atla +00000004: 940C0034 JMP 0x00000034 Atla +00000006: 940C0034 JMP 0x00000034 Atla +00000008: 940C0034 JMP 0x00000034 Atla 0000000E: 940C0034 JMP 0x00000034 Atla +00000010: 940C0034 JMP 0x00000034 Atla +00000012: 940C0034 JMP 0x00000034 Atla +00000014: 940C0034 JMP 0x00000034 Atla +00000016: 940C0034 JMP 0x00000034 Atla : 940C0034 JMP 0x00000034 Atlama +0000001E: 940C0034 JMP 0x00000034 Atlama +00000020: 940C0034 JMP 0x00000034 Atlama +00000022: 940C0034 JMP 0x00000034 Atlama +00000024: 940C0034 JMP 0x00000034 Atlama +00000026: 040C0034000MP Atlama

00000000: 940C002A JMP 0x0000002A Atla +00000002: 940C0034 JMP 0x00000034 Atla +00000004: 940C0034 JMP 0x00000034 Atla +00000006: 940C0034 JMP 0x00000034 Atla +00000008: 940C0034 JMP 0x00000034 Atla Atlama 940C0034 JMP 0x00000034 Atlama +0000001E: 940C0034 JMP 0x00000034 Atlama +00000020: 940C0034 JMP 0x00000034 Atlama +00000022: 940C0034 JMP 0x00000034 Atlama +00000024: 940C0034 JMP 0x00000034 Atlama +0003400026: Atlama 0x0000000004 JMP

Bu, kesme vektör tablosudur. Ona daha sonra döneceğiz, şimdilik sadece bakın ve orada olduğunu hatırlayın. İlk sütun, komutun bulunduğu flaş hücresinin adresi, ikincisi komut kodu, üçüncü komut anımsatıcısı, aynı montajcı talimatı, komutun üçüncü işlenenleridir. Oh, ve otomatik yorum.
Yani bakarsanız, sürekli geçişler vardır. Ve JMP komut kodu dört bayttır, geriye doğru yazılmış atlama adresini içerir - düşük adresteki düşük bayt ve atlama komut kodu 940C

0000002B: BE1F OUT 0x3F,R1 Out to I/O konumuna

0x3F adresine bu sıfırı yazın.I/O view sütununa bakarsanız 0x3F adresinin SREG registerının adresi olduğunu göreceksiniz - controller flag register. Şunlar. programı sıfır koşullarda çalıştırmak için SREG'i sıfırlıyoruz.

1 2 3 4 +0000002C: E5CF LDI R28,0x5F Hemen yükle +0000002D: E0D4 LDI R29,0x04 Hemen yükle +0000002E: BFDE OUT 0x3E,R29 I/O konumuna Çıkış +0000002F: BFCD OUT 0x3D,R28 Out to I/O konumuna

0000002C: E5CF LDI R28,0x5F Hemen yükle +0000002D: E0D4 LDI R29,0x04 Hemen yükle +0000002E: BFDE OUT 0x3E,R29 I/O konumuna Çıkış +0000002F: BFCD OUT 0x3D,R28 Out to I/O konumuna

Bu yığın işaretçisini yüklüyor. Kayıtları doğrudan G / Ç'ye yükleyemezsiniz, yalnızca bir ara kayıt aracılığıyla. Bu nedenle, önce LDI'ye orta, ardından OUT'dan I/O'ya. Ayrıca size yığın hakkında daha fazla bilgi vereceğim. Bu arada bilin ki bu çok dinamik bir hafıza alanıdır, RAM'in sonunda takılır ve adresleri ve ara değişkenleri kendi içinde saklar. Şimdi yığının nereden başlayacağını belirttik.

00000032: 940C0041 JMP 0x00000041 Atlama

Programın saaaaamy sonuna bir atlama ve orada devre dışı bırakılmış ve kendi kendine sıkıca döngü yapan kesintiler var:

1 2 +00000041: 94F8 CLI Global Interrupt Disable +00000042: CFFF RJMP PC-0x0000 Göreli atlama

00000041: 94F8 CLI Global Interrupt Disable +00000042: CFFF RJMP PC-0x0000 Göreli atlama

Bu, ana işlevden çıkış gibi öngörülemeyen durumlarda geçerlidir. Denetleyici böyle bir döngüden ya bir donanım sıfırlamasıyla ya da daha büyük olasılıkla bir bekçi köpeğinden sıfırlamayla çıkarılabilir. Ya da, yukarıda söylediğim gibi, bu yerleri hex editöründe düzeltin ve istediğimiz yere sürün. Ayrıca JMP ve RJMP olmak üzere iki tür atlama olduğuna dikkat edin, ilki bir adrese doğrudan atlamadır. Dört bayt kaplar ve tüm bellek alanı üzerinde doğrudan bir atlama yapabilir. İkinci geçiş türü - RJMP - görecelidir. Komutu iki bayt alır, ancak mevcut konumdan (adres) 1024 adım ileri veya geri atlar. Ve parametreleri mevcut noktadan ofseti gösterir. Daha sık kullanılır, tk. flaştaki alanın yarısını kaplar ve uzun geçişlere nadiren ihtiyaç duyulur.

1 +00000034: 940C0000 JMP 0x00000000 Atlama

00000034: 940C0000 JMP 0x00000000 Atlama

Ve bu, kodun en başına bir atlamadır. Bir çeşit yeniden başlatma. Tüm vektörlerin burada atlayıp atlamadığını kontrol edebilirsiniz. Bu sonuca göre - şimdi kesintileri etkinleştirirseniz (varsayılan olarak devre dışı bırakılırlar) ve bir kesintiniz varsa, ancak işleyici yoksa, o zaman bir yazılım sıfırlaması olacak - program en başa atılacaktır.

ana işlev. Her şey aynı, tarif bile edemezsin. Sadece kayıtlara bakın, önceden hesaplanmış sayı girilir. Derleyici önişlemci kayaları !!! Yani "sihirli" sayılar yok!

1 2 3 4 5 6 7 8 9 10 11 12 <

00000036: E383 LDI R24,0x33 Hemen yükle +00000037: B989 OUT 0x09,R24 Out to I/O konumu 15: UBRRH = HI(bauddivider); +00000038: BC10 OUT 0x20,R1 Out to I/O konumu 16: UCSRA = 0; +00000039: B81B OUT 0x0B,R1 Out to I/O konumu 17: UCSRB = 1<

Ve işte söve:

1 2 3 +0000003E: E080 LDI R24,0x00 Hemen yükle +0000003F: E090 LDI R25,0x00 Hemen yükle +00000040: 9508 RET Alt program dönüşü

0000003E: E080 LDI R24,0x00 Hemen yükle +0000003F: E090 LDI R25,0x00 Hemen yükle +00000040: 9508 RET Alt program dönüşü

Soru şu ki, derleyici neden bu tür üstleri ekliyor? Ve bu Return 0'dan başka bir şey değil, o zaman işlevi int main (void) olarak tanımladık, bu yüzden dört bayt daha mahvettik, ne olduğunu anlamıyorum :) Ve void main (void) yaparsanız sadece RET kalır, ancak ana işlevimizin hiçbir şey döndürmediğini söyleyen bir uyarı görünecektir. Genel olarak, ne istersen onu yap :)

Zor? Öyle değil gibi görünüyor. Sökücü modunda adım adım yürütmeye tıklayın ve işlemcinin kayıtlarla gerçekleşen bireysel talimatları nasıl yürüttüğünü görün. Komutlar ve son döngü arasındaki hareket nasıl.

Birkaç gün sonra devam edecek...

Üstü kapalı:
Alexey78 Firefox için sitemde ve forumda gezinmeyi kolaylaştıran bir eklenti yaptım.
Tartışma ve indirme,

AVR mikrodenetleyicileri için çeşitli programlama dilleri vardır, ancak bu diller, mikrodenetleyici donanımını kontrol etmek için gerekli tüm yeteneklerin en iyi şekilde uygulanmasını sağladığından, belki de en uygun olan assembler ve C'dir.

Assembler, mikrodenetleyicinin doğrudan komut setini kullanan düşük seviyeli bir programlama dilidir. Bu dilde bir program oluşturmak, programlanabilir çipin komut sistemi hakkında iyi bir bilgi ve programı geliştirmek için yeterli zaman gerektirir. Assembler, program geliştirme hızı ve kolaylığı açısından C'ye kaybeder, ancak son yürütülebilir kodun boyutunda ve buna bağlı olarak yürütme hızında gözle görülür avantajlara sahiptir.

C, geliştiriciye üst düzey bir dilin tüm avantajlarını vererek, çok daha rahat programlar oluşturmanıza olanak tanır.
AVR mimarisi ve komut sisteminin, C derleyicisinin geliştiricilerinin doğrudan katılımıyla oluşturulduğu ve bu dilin özelliklerini dikkate aldığı bir kez daha belirtilmelidir. C ile yazılmış kaynak kodu derlemek hızlıdır ve kompakt, verimli kod üretir.

C'nin birleştiriciye göre başlıca avantajları şunlardır: yüksek hızlı program geliştirme; mikrodenetleyicinin mimarisi hakkında kapsamlı bir çalışma gerektirmeyen çok yönlülük; algoritmanın daha iyi belgelenebilirliği ve okunabilirliği; fonksiyon kitaplıklarının mevcudiyeti; kayan nokta hesaplamaları için destek.

C dili, düşük seviyeli programlamanın yeteneklerini yüksek seviyeli bir dilin özellikleriyle uyumlu bir şekilde birleştirir. Düşük seviyeli programlama yeteneği, doğrudan donanım üzerinde çalışmayı kolaylaştırır ve yüksek seviyeli dil özellikleri, kolayca okunabilir ve değiştirilebilir program kodunun oluşturulmasına izin verir. Ek olarak, neredeyse tüm C derleyicileri, yürütme süresi ve kaynakları açısından programın kritik bölümlerini yazmak için assembler eklerini kullanma yeteneğine sahiptir.

Tek kelimeyle, C, hem yeni başlayanlar için AVR mikro denetleyicileri hem de ciddi geliştiriciler ile tanışmak için en uygun dildir.

Derleyiciler, programın kaynak kodunu bir mikrodenetleyici ürün yazılımı dosyasına dönüştürmek için kullanılır.

Atmel, Windows tabanlı Atmel Studio geliştirme ortamına dahil olan güçlü bir derleyici derleyici sağlar. Derleyici ile birlikte geliştirme ortamı bir hata ayıklayıcı ve bir öykünücü içerir.
Atmel Studio tamamen ücretsizdir ve Atmel web sitesinde mevcuttur.

Şu anda AVR için epeyce C derleyicisi var. Bunların en güçlüsü Stockholm'den IAR Systems'ın derleyicisidir. 90'lı yılların ortalarında AVR komut sisteminin geliştirilmesine katılan çalışanlarıydı. IAR C Derleyici, kapsamlı kod optimizasyon yeteneklerine sahiptir ve ayrıca bir derleyici derleyicisi, bir bağlayıcı, bir proje ve kitaplık yöneticisi ve bir hata ayıklayıcı içeren IAR Embedded Workbench (EWB) entegre geliştirme ortamının bir parçası olarak gelir. Paketin tam sürümünün fiyatı 2820 EUR'dur. Şirketin web sitesinde, 30 gün boyunca ücretsiz bir değerlendirme sürümünü veya 4 KB kod boyutu sınırına sahip sınırsız bir sürümü indirebilirsiniz.

Palo Alto, California'dan Amerikan şirketi Image Craft, oldukça geniş bir popülerlik kazanmış olan C dili için bir derleyici üretiyor. AVR için JumpStart C, kabul edilebilir kod optimizasyonuna sahiptir ve çok pahalı değildir (versiyona bağlı olarak 50$ ile 499$ arasında). AVR için JumpStart C'nin demo versiyonu 45 gün boyunca tamamen işlevseldir.

Rumen Code Vision AVR C Derleyicisi daha az popülerlik kazanmadı, bu derleyicinin tam sürümünün fiyatı nispeten düşük ve 150 EUR tutarında. Derleyici, standart özelliklere ek olarak oldukça ilginç bir özellik içeren entegre bir geliştirme ortamıyla birlikte gelir - CodeWizardAVR Otomatik Program Oluşturucu. Geliştirme ortamında bir seri terminalin varlığı, mikrodenetleyicinin seri portunu kullanarak programlarda hata ayıklamaya izin verir. Geliştiriciler, kod boyutu sınırı 4 KB olan ve oluşturulan C kaynak kodunun kaydedilmesinin devre dışı bırakıldığı ücretsiz bir değerlendirme sürümünü indirebilir.

Sırbistan'ın Belgrad şehrinde bulunan MikroElektronika, AVR mikrodenetleyicileri için bütün bir derleyici ailesi üretiyor. AVR için mikroC PRO adlı bir C derleyicisinin maliyeti 249 dolar. Aynı fiyata mikroBasic ve mikroPascal da var. Geliştiricinin sitesinde kod boyutu sınırı 4096 bayt olan demolar var. Bu derleyici ailesinin avantajı, yalnızca diller arasında değil, aynı zamanda mikro denetleyiciler arasında da kolay geçiş sağlayabilen tek bir platform ve tek bir ideolojidir (PIC, STM32, 8051 ... için derleyici sürümleri vardır).

Entegre geliştirme ortamı gerçekten ikonik hale geldi. Güçlü C ve derleyici derleyicileri, bir AVRDUDE programcısı, bir hata ayıklayıcı, bir simülatör ve diğer birçok destekleyici program ve yardımcı program içerir. WinAVR, Atmel'in AVR Studio geliştirme ortamıyla mükemmel bir şekilde bütünleşir. Montajcı, giriş kodunda AVR Studio montajcısı ile aynıdır. C ve montajcı derleyicileri, yalnızca yerleşik araçları kullanmanıza değil, aynı zamanda güçlü AVR Studio simülatörünü kullanmanıza izin veren COFF formatında hata ayıklama dosyaları oluşturma yeteneğine sahiptir. Bir diğer önemli artı, WinAVR'nin kısıtlama olmaksızın ücretsiz olarak dağıtılmasıdır (üreticiler GNU Genel Kamu Lisansını desteklemektedir).

Özet olarak, WinAVR, AVR mikro denetleyicilerinde ustalaşmaya başlayanlar için ideal bir seçimdir. Bu kursta ana olarak kabul edilen bu geliştirme ortamıdır.

Bitsel işlemler, daha önce ele aldığımız mantıksal işlemlere dayanır. AVR mikro denetleyicilerinin ve diğer türlerin programlanmasında önemli bir rol oynarlar. Neredeyse hiçbir program bitsel işlemler kullanmadan yapamaz. Şimdiye kadar, MK programlamayı öğrenmeyi kolaylaştırmak için kasıtlı olarak bunlardan kaçındık.

Önceki tüm makalelerde, yalnızca G / Ç bağlantı noktalarını programladık ve zamanlayıcılar, analogdan dijitale dönüştürücüler, kesintiler ve olmadan MK'nin tüm gücünü kaybettiği diğer dahili cihazlar gibi ek yerleşik düğümler kullanmadık.

Yerleşik MK cihazlarında uzmanlaşmaya geçmeden önce, AVR MK kayıtlarının ayrı bitlerini nasıl kontrol edeceğinizi veya kontrol edeceğinizi öğrenmeniz gerekir. Önceden, bir kerede tüm kaydın bitlerini kontrol ettik veya ayarladık. Farkın ne olduğunu görelim ve daha sonra devam edelim.

Bitsel İşlemler

Çoğu zaman, AVR mikrodenetleyicilerini programlarken, acemi MK programcılarına kıyasla daha fazla netliğe sahip olduğu ve onlar için iyi anlaşıldığı için onu kullandık. Örneğin D portunun sadece 3. bitini ayarlamamız gerekiyor. Bunun için zaten bildiğimiz gibi aşağıdaki ikili kodu kullanabiliriz:

PORTD = 0b00001000;

Ancak bu komut ile 3. biti bire ayarlıyoruz ve diğerlerini (0, 1, 2, 4, 5, 6 ve 7.) sıfırlıyoruz. Ve şimdi 6. ve 7. hanelerin ADC girişleri olarak kullanıldığını ve bu sırada MK'nin ilgili çıkışlarına bazı cihazlardan bir sinyal geldiğini ve yukarıdaki komutu kullanarak bu sinyalleri sıfırladığımızı hayal edelim. Sonuç olarak mikrodenetleyici onları görmez ve sinyallerin gelmediğine inanır. Bu nedenle, böyle bir komut yerine, sadece 3. biti bire ayarlayacak ve diğer bitleri etkilemeyecek başka bir komut kullanmalıyız. Bunun için genellikle aşağıdaki bitsel işlem kullanılır:

LİMAN |= (1<<3);

Sözdizimini aşağıda ayrıntılı olarak analiz edeceğiz. Ve şimdi başka bir örnek. Diyelim ki PIND kaydının 3. bitinin durumunu kontrol etmemiz gerekiyor, böylece düğmenin durumunu kontrol ediyoruz. Bu bit sıfırlanırsa, düğmeye basıldığını ve ardından basılan düğmenin durumuna karşılık gelen komut kodunun yürütüldüğünü biliyoruz. Önceden, aşağıdaki gösterimi kullanırdık:

if (pind == 0b00000000)

(herhangi bir kod)

Bununla birlikte, onun yardımıyla, tek bir tanesini değil, - 3., ancak PIND kaydının tüm bitlerini bir kerede kontrol ediyoruz. Bu nedenle, butona basılsa ve istenen bit sıfırlansa bile, ancak o sırada başka bir port D pininde bir sinyal alınsa bile, karşılık gelen bit bire ayarlanacak ve parantez içindeki koşul yanlış olacaktır. Sonuç olarak, kaşlı parantez içindeki kod, düğmeye basıldığında bile yürütülmeyecektir. Bu nedenle, PIND kaydının tek bir 3. bitinin durumunu kontrol etmek için bit düzeyinde bir işlem kullanılmalıdır:

if (~PIND & (1<<3))

(herhangi bir kod)

Bireysel mikrodenetleyici bitleriyle çalışmak için, C programlama dilinin cephaneliğinde, bir veya daha fazla bireysel bitin durumunu bir kerede değiştirebileceğiniz veya kontrol edebileceğiniz vardır.

Tek bir bitin ayarlanması

D bağlantı noktası gibi tek bir bit ayarlamak için bit düzeyinde OR işlemi kullanılır. Yazının başında kullandığımız şey buydu.

PORTD = 0b00011100; // başlangıç ​​değeri

PORTD = PORTD | (bir<<0); применяем побитовую ИЛИ

LİMAN |= (1<<0); // сокращенная форма записи

PORTD == 0b00011101; // sonuç

Bu komut, biti sıfıra ayarlar ve gerisini değiştirmeden bırakır.

Örneğin, D portunun 6. bitini ayarlayalım.

PORTD = 0b00011100; // ilk bağlantı noktası durumu

LİMAN |= (1<<6); //

PORTD == 0b01011100; // sonuç

Bir kerede birden çok ayrı bit yazmak için, örneğin, sıfır, altıncı ve yedinci bağlantı noktası B aşağıdaki gösterim geçerlidir.

PORTB = 0b00011100; // başlangıç ​​değeri

PORTB |= (1<<0) | (1<<6) | (1<<7); //

PORTB == 0b1011101; // sonuç

Bireysel bitlerin sıfırlanması (sıfırlanması)

Tek bir biti sıfırlamak için, daha önce tartışılan üç komut aynı anda kullanılır: .

PORTC kaydının 3. bitini sıfırlayalım ve gerisini değiştirmeden bırakalım.

PORTC = 0b00011100;

PORTC &= ~(1<<3);

PORTC == 0b00010100;

2. ve 4. basamak için benzer işlemleri yapalım:

PORTC = 0b00111110;

PORTC &= ~((1<<2) | (1<<4));

PORTC == 0b00101010;

ritmi değiştirmek

Ayarlama ve sıfırlamaya ek olarak, tek bir biti zıt duruma geçiren kullanışlı bir komut da kullanılır: bir sıfıra ve tam tersi. Bu mantıksal işlem, örneğin bir Yılbaşı çelengi gibi çeşitli aydınlatma efektlerinin yapımında yaygın olarak kullanılır. PORTA örneğini düşünün

PORTA = 0b00011111;

PORTA ^= (1<<2);

PORTA == 0b00011011;

Sıfır, ikinci ve altıncı bitlerin durumunu değiştirin:

PORTA = 0b00011111;

PORTA ^= (1<<0) | (1<<2) | (1<<6);

PORTA == 0b01011010;

Tek bir bitin durumunu kontrol etme. Bir I/O portunun kontrol edilmesinin (yazmanın aksine) PIN kaydından veri okunarak gerçekleştirildiğini hatırlatmama izin verin.

En yaygın test, iki döngü ifadesinden biri tarafından gerçekleştirilir: if ve while. Bu operatörlere daha önceden aşinayız.

Mantıksal bir sıfır (sıfırlama) varlığı için deşarjın kontrol edilmesi eğer

if (0==(PIND & (1)<<3)))

D portunun üçüncü biti temizlenirse, Kod1 yürütülür. Aksi takdirde, Code2 yürütülür.

Benzer eylemler, bu kayıt biçiminde ve bu kayıt biçiminde gerçekleştirilir:

if (~PIND & (1<<3))

İle mantıksal bir birimin (ayarın) varlığı için deşarjın kontrol edilmesi eğer

if (0 != (PIND & (1)<<3)))

if (PIND & (1<<3))

Yukarıdaki iki döngü benzer şekilde çalışır, ancak C programlama dilinin esnekliği nedeniyle farklı şekilde yazılabilirler. != işlemi eşit değil anlamına gelir. PD G/Ç bağlantı noktasının üçüncü biti (bir) ayarlanmışsa, Kod1, değilse Kod2 yürütülür.

ile biraz sıfırlama bekleniyor süre

while (PIND & (1<<5))

PIND kaydının 5. biti ayarlandığı sürece Kod1 yürütülecektir. Sıfırlamak, Code2'yi yürütmeye başlayacaktır.

Bitin ayarlanmasını bekliyorum süre

Burada, C dilinin sözdizimi, en yaygın iki yoldan kod yazmanıza izin verir. Pratikte her iki kayıt türü de kullanılır.