STM32, σειριακή διεπαφή I2C. STM32, σειριακή διεπαφή I2C Stm32 διεπαφή i2c Η περιγραφή συνεχίστηκε

Σε άλλους αρέσουν οι πίτες, σε άλλους όχι.

Η διεπαφή i2c είναι ευρέως διαδεδομένη και χρησιμοποιείται. Στο stm32f4 υπάρχουν έως και τρεις ενότητες που υλοποιούν αυτό το πρωτόκολλο.
Φυσικά, με πλήρης υποστήριξηόλο αυτό το πράγμα.

Η εργασία με τη μονάδα είναι, γενικά, η ίδια όπως σε άλλους ελεγκτές: της δίνετε εντολές, τις εκτελεί και αναφέρει το αποτέλεσμα:
I> Πήγαμε START.
S> Εντάξει, το έστειλα.
Me> Cool, στείλε τη διεύθυνση τώρα. Όπως αυτό: 0xXX.
S> Εντάξει, το έστειλα. Μου είπαν ότι ACK. Ας προχωρήσουμε.
I> Ακόμα ζωντανός, καλά. Εδώ είναι ο αριθμός μητρώου: 0xYY, - πάμε.
S> Στάλθηκε, ελήφθη ACK.
I> Τώρα στείλτε του τα δεδομένα, ορίστε το byte: 0xZZ.
S> Στάλθηκε, συμφωνεί σε περισσότερα: ACK.
Γάμησέ τον, όχι ακόμα. Πήγαν ΣΤΟΠ.
S> Εντάξει.

Και όλα είναι περίπου σε αυτό το πνεύμα.

ΣΕ αυτόν τον ελεγκτήΟι ακίδες i2c είναι διάσπαρτες στις θύρες ως εξής:
PB6: I2C1_SCL
PB7: I2C1_SDA

PB8: I2C1_SCL
PB9: I2C1_SDA

PB10: I2C2_SCL
PB11: I2C2_SDA

PA8: I2C3_SCL
PC9: I2C3_SDA
Γενικά, είναι βολικό να κοιτάξετε το pinout των περιφερειακών στη σελίδα 59.

Παραδόξως, για να εργαστείτε με το i2c χρειάζεστε όλα τα μητρώα του, ευτυχώς υπάρχουν λίγα από αυτά:
I2C_CR1- εντολές στη μονάδα για αποστολή εντολών/καταστάσεων και επιλογή τρόπων λειτουργίας.
I2C_CR2- ρύθμιση DMA και ένδειξη της συχνότητας λειτουργίας της μονάδας (2-42 MHz).
I2C_OAR1- ρύθμιση της διεύθυνσης της συσκευής (για την υποτελή), του μεγέθους διεύθυνσης (7 ή 10 bit).
I2C_OAR2- ρύθμιση της διεύθυνσης της συσκευής (αν υπάρχουν δύο διευθύνσεις).
I2C_DR- μητρώο δεδομένων·
I2C_SR1- Μητρώο κατάστασης ενότητας.
I2C_SR2- καταχωρητής κατάστασης (slave, πρέπει να διαβαστεί εάν οι σημαίες ADDR ή STOPF έχουν οριστεί στο SR1).
I2C_CCR- ρύθμιση της ταχύτητας διεπαφής.
I2C_TRISE- ρύθμιση χρονισμών των άκρων.

Ωστόσο, οι μισοί από αυτούς είναι του τύπου «γράψτε το και ξεχάστε το».

Η πλακέτα STM32F4-Discovery διαθέτει ήδη μια συσκευή I2C με την οποία μπορείτε να εξασκηθείτε: CS43L22, DAC ήχου. Συνδέεται με ακίδες PB6/PB9. Το κύριο πράγμα είναι να μην ξεχάσετε να εφαρμόσετε ένα υψηλό επίπεδο για να καρφώσετε το PD4 (~Η RESET κάθεται εκεί), διαφορετικά το DAC δεν θα ανταποκριθεί.

Η διαδικασία εγκατάστασης είναι περίπου η εξής:
1 . Επιτρέψτε το ρολόι των θυρών και της ίδιας της μονάδας.
Χρειαζόμαστε ακίδες PB6/PB9, επομένως πρέπει να ορίσουμε το bit 1 (GPIOBEN) στον καταχωρητή RCC_AHB1ENR για να ενεργοποιήσουμε τη θύρα.
Και ορίστε το bit 21 (I2C1EN) στον καταχωρητή RCC_APB1ENR για να ενεργοποιήσετε τη μονάδα I2C. Για τη δεύτερη και την τρίτη ενότητα, οι αριθμοί bit είναι 22 και 23, αντίστοιχα.
2 . Στη συνέχεια, οι ακίδες διαμορφώνονται: Έξοδος Oped Drain (GPIO->OTYPER), εναλλακτική λειτουργία λειτουργίας (GPIO->MODER) και εναλλακτικός αριθμός λειτουργίας (GPIO->AFR).
Εάν θέλετε, μπορείτε να διαμορφώσετε ένα pull-up (GPIO->PUPDR), εάν δεν βρίσκεται στην πλακέτα (και απαιτείται ανάσυρση στο τροφοδοτικό και των δύο γραμμών σε οποιαδήποτε μορφή). Ο αριθμός για το I2C είναι πάντα ο ίδιος: 4. Είναι ωραίο που υπάρχει ξεχωριστός αριθμός για κάθε τύπο περιφερειακού.
3 . Η τρέχουσα συχνότητα ρολογιού της περιφερειακής συσκευής Fpclk1 (εκφρασμένη σε MHz) υποδεικνύεται στον καταχωρητή CR2. Όπως καταλαβαίνω, αυτό είναι απαραίτητο για τον υπολογισμό διαφορετικών χρονισμών πρωτοκόλλου.
Παρεμπιπτόντως, θα πρέπει να είναι τουλάχιστον δύο για την κανονική λειτουργία και τουλάχιστον τέσσερις για τη γρήγορη λειτουργία. Και αν χρειάζεστε πλήρη ταχύτητα 400 kHz, τότε πρέπει επίσης να διαιρεθεί με το 10 (10, 20, 30, 40 MHz).
Μέγιστη επιτρεπόμενη συχνότητα ρολογιού: 42 MHz.
4 . Η ταχύτητα διασύνδεσης διαμορφώνεται στον καταχωρητή CCR και επιλέγεται η λειτουργία (κανονική/γρήγορη).
Το νόημα είναι: Tsck = CCR * 2 * Tpckl1, δηλ. η περίοδος SCK είναι ανάλογη του CCR (για τη γρήγορη λειτουργία όλα είναι λίγο πιο δύσκολα, αλλά περιγράφονται στο RM).
5 . Ο μέγιστος χρόνος ανόδου ακμής στον καταχωρητή TRISE ρυθμίζεται. Για την τυπική λειτουργία αυτός ο χρόνος είναι 1 µs. Στο μητρώο πρέπει να γράψετε τον αριθμό των κύκλων διαύλου που χωρούν σε αυτόν τον χρόνο, συν ένα:
αν ο κύκλος Tpclk1 διαρκεί 125 ns, τότε γράψτε (1000 ns / 125 ns) + 1 = 8 + 1 = 9.
6 . Η δημιουργία σημάτων διακοπής (σφάλμα, κατάσταση και δεδομένα) είναι προαιρετικά ενεργοποιημένη.
7 . Η μονάδα ενεργοποιείται: η σημαία PE στον καταχωρητή CR1 έχει οριστεί σε 1.

Στη συνέχεια, η ενότητα λειτουργεί όπως θα έπρεπε. Απλά πρέπει να εφαρμόσετε τη σωστή σειρά εντολών και να ελέγξετε τα αποτελέσματα. Για παράδειγμα, μια καταχώρηση μητρώου:
1 . Πρώτα πρέπει να στείλετε START ορίζοντας μια σημαία με το ίδιο όνομα στον καταχωρητή CR1. Εάν όλα είναι εντάξει, τότε μετά από κάποιο χρονικό διάστημα η σημαία SB θα οριστεί στον καταχωρητή SR1.
Θα ήθελα να σημειώσω ένα σημείο - εάν δεν υπάρχει pull-up στη γραμμή (και είναι στο 0), τότε αυτή η σημαία μπορεί να μην περιμένει καθόλου.
2 . Εάν ληφθεί η σημαία, τότε στέλνουμε τη διεύθυνση. Για μια διεύθυνση επτά bit, απλώς τη γράφουμε σε DR ακριβώς όπως θα είναι στη γραμμή (7 bit διεύθυνσης + bit κατεύθυνσης). Για δέκα bit, ένας πιο σύνθετος αλγόριθμος.
Εάν η συσκευή ανταποκριθεί στη διεύθυνση με ACK, τότε η σημαία ADDR θα εμφανιστεί στον καταχωρητή SR1. Εάν όχι, τότε θα εμφανιστεί η σημαία AF (Acknowledge dështim).
Εάν εμφανιστεί το ADDR, πρέπει να διαβάσετε τον καταχωρητή SR2. Δεν χρειάζεται να κοιτάξετε τίποτα εκεί, απλώς η διαδοχική ανάγνωση των SR1 και SR2 επαναφέρει αυτήν τη σημαία. Και ενώ η σημαία έχει οριστεί, το SCL διατηρείται χαμηλά από τον κύριο, κάτι που είναι χρήσιμο εάν χρειαστεί να ζητήσετε από την απομακρυσμένη συσκευή να περιμένει πριν στείλει δεδομένα.
Εάν όλα είναι εντάξει, τότε η μονάδα θα μεταβεί στη λειτουργία λήψης ή μετάδοσης δεδομένων, ανάλογα με το λιγότερο σημαντικό bit της απεσταλμένης διεύθυνσης. Για τη γραφή πρέπει να είναι μηδέν, για την ανάγνωση πρέπει να είναι ένα.
αλλά κοιτάμε το ρεκόρ, οπότε θα υποθέσουμε ότι υπήρχε ένα μηδέν εκεί.
3 . Στη συνέχεια στέλνουμε τη διεύθυνση του μητρώου που μας ενδιαφέρει. Με τον ίδιο τρόπο, γράφοντάς το στο DR. Μετά τη μετάδοση, ορίζονται οι σημαίες TXE (το buffer μετάδοσης είναι άδειο) και BTF (ολοκληρώθηκε η μεταφορά).
4 . Στη συνέχεια έρχονται τα δεδομένα που μπορούν να σταλούν ενώ η συσκευή απαντά με ACK. Εάν η απόκριση είναι NACK, αυτές οι σημαίες δεν θα οριστούν.
5 . Με την ολοκλήρωση της μεταφοράς (ή σε περίπτωση απροσδόκητης συνθήκης), στέλνουμε STOP: η σημαία με το ίδιο όνομα ορίζεται στον καταχωρητή CR1.

Κατά την ανάγνωση, όλα είναι ίδια. Αλλάζει μόνο μετά την εγγραφή της διεύθυνσης μητρώου.
Αντί να γράψετε δεδομένα, αποστέλλεται ξανά START (επανεκκίνηση) και η διεύθυνση αποστέλλεται με το λιγότερο σημαντικό σύνολο bit (σύμβολο ανάγνωσης).
Η μονάδα θα περιμένει για δεδομένα από τη συσκευή. Για να το ενθαρρύνετε να στείλει τα επόμενα byte, πρέπει να ορίσετε τη σημαία ACK στο CR1 πριν τη λήψη (έτσι ώστε μετά τη λήψη η μονάδα να στείλει το ίδιο ACK).
Όταν το βαρεθείτε, αφαιρέστε τη σημαία, η συσκευή θα δει NACK και θα σιωπήσει. Μετά από αυτό στέλνουμε STOP με τον συνηθισμένο τρόπο και χαιρόμαστε για τα δεδομένα που λάβαμε.

Εδώ είναι το ίδιο πράγμα σε μορφή κώδικα:
// Εκκίνηση της μονάδας void i2c_Init(void) ( uint32_t Ρολόι = 16000000UL; // Συχνότητα ρολογιού μονάδας (δεν χρησιμοποιείται το system_stm32f4xx.c) uint32_t Ταχύτητα = 100000UL; // 100 kHz με δυνατότητα κλειδώματος PICC-R// |= RCC_AHB1ENR_GPIOBEN; // Ρυθμίστε τις ακίδες PB6, PB9 // Ανοίξτε την αποστράγγιση! GPIOB->OTYPER |= GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_9; // Το pull-up είναι εξωτερικό, επομένως δεν μπορεί να ρυθμιστεί εδώ, εάν είναι απαραίτητο! // δείτε τον καταχωρητή GPIOB->PUPDR // Αριθμός της εναλλακτικής συνάρτησης GPIOB ->AFR &= ~(0x0FUL<< (6 * 4)); // 6 очистим GPIOB->AFR |= (0x04UL<< (6 * 4)); // В 6 запишем 4 GPIOB->AFR &= ~(0x0FUL<< ((9 - 8) * 4)); // 9 очистим GPIOB->AFR |= (0x04UL<< ((9 - 8) * 4)); // В 9 запишем 4 // Режим: альтернативная функция GPIOB->MODER &= ~((0x03UL<< (6 * 2)) | (0x03UL << (9 * 2))); // 6, 9 очистим GPIOB->MODER |= ((0x02UL<< (6 * 2)) | (0x02UL << (9 * 2))); // В 6, 9 запишем 2 // Включить тактирование модуля I2C1 RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // Σε αυτό το σημείο το I2C θα πρέπει να απενεργοποιηθεί // Επαναφορά όλων (SWRST == 1, επαναφορά) I2C1->CR1 = I2C_CR1_SWRST; // PE == 0, αυτό είναι το κύριο πράγμα I2C1->CR1 = 0; // Υποθέτουμε ότι τρέχουμε από RC (16 MHz) // Δεν υπάρχουν προκλιμακωτές στο σύστημα ρολογιού (όλα 1) // Με φιλικό τρόπο, θα πρέπει να τα υπολογίσουμε όλα αυτά από // την πραγματική συχνότητα ρολογιού της μονάδας I2C1->CR2 = Ρολόι / 1000000UL; // 16 MHz // Προσαρμόστε τη συχνότητα ( // Tclk = (1 / Fperiph); // Μηρός = Tclk * CCR; // Tlow = Μηρός; // Fi2c = 1 / CCR * 2; // CCR = Fperiph / ( Fi2c * 2); uint16_t Τιμή = (uint16_t) (Ρολόι / (Ταχύτητα * 2)); // Ελάχιστη τιμή: 4 if(Τιμή< 4) Value = 4; I2C1->CCR = Τιμή; ) // Ρυθμίστε τον χρόνο αύξησης ορίου // Στην τυπική λειτουργία, αυτός ο χρόνος είναι 1000 ns // Απλώς προσθέτουμε ένα στη συχνότητα που εκφράζεται σε MHz (βλ. RM σελ. 604). I2C1->TRISE = (Ρολόι / 1000000UL) + 1; // Ενεργοποίηση λειτουργικής μονάδας I2C1->CR1 |= (I2C_CR1_PE); ( (); // Καταχώρηση διεύθυνσης if(!i2c_SendData(Register)) return i2c_SendStop(); // Δεδομένα if(!i2c_SendData(Data)) return i2c_SendStop(); // Stop! i2c_SendStop(); return true; ) // Λήψη byte bool i2c_ReceiveByte(uint8_t Διεύθυνση, uint8_t Εγγραφή, uint8_t * Δεδομένα) ( if(!i2c_SendStart()) επιστροφή false; // Διεύθυνση τσιπ if(!i2c_SendAddress(Διεύθυνση)) επιστροφή i2c_SendSendStop διεύθυνση if(!) i2c_SendData(Register)) return i2c_SendStop(); // Restart if(!i2c_SendStart()) return false; // Chip address (read) if(!i2c_SendAddress(Address | 1)) return i2c_SendStop(); // Receive a byte if(!i2c_ReceiveData(Data)) return i2c_SendStop(); // Stop! i2c_SendStop(); return true; ) Χρήση: ( uint8_t ID = 0; i2c_Init(); // Υποθέτουμε ότι το PD4 έχει οριστεί σε υψηλό επίπεδο και το DAC λειτουργεί (αυτό πρέπει να γίνει με κάποιο τρόπο) // Στείλτε ένα byte στη συσκευή με διεύθυνση 0x94, για να καταχωρήσετε 0x00 με την τιμή 0x00. i2c_SendByte(0x94, 0x00, 0x00); // Λήψη ενός byte από τη συσκευή με διεύθυνση 0x94 από τον καταχωρητή 0x01 (ID) στη μεταβλητή buffer i2c_ReceiveByte(0x94, 0x01, &ID); )
Φυσικά, δεν μπορείτε να το κάνετε αυτό παρά μόνο σε ένα παράδειγμα εκπαίδευσης. Η αναμονή για την ολοκλήρωση της ενέργειας είναι πολύ μεγάλη για έναν τόσο γρήγορο ελεγκτή.

(Οδηγός προγραμματιστή για μικροελεγκτές οικογένειας HCS08)

Για τον έλεγχο της μονάδας I2C, χρησιμοποιούνται 6 ειδικοί καταχωρητές συναρτήσεων:

  • IICC - πρώτος καταχωρητής ελέγχου της μονάδας I2C.
  • IICC2 - δεύτερος καταχωρητής ελέγχου της μονάδας I2C.
  • IICS - μητρώο κατάστασης μονάδας I2C.
  • Καταχωρητής ρυθμού baud της μονάδας IICF - I2C.
  • IICA - Καταχωρητής διευθύνσεων μονάδας I2C.
  • Το IICD είναι ο καταχωρητής δεδομένων της μονάδας I2C.

Το MCU της σειράς QE περιέχει 2 μονάδες I2C και, κατά συνέπεια, δύο καταχωρητές ελέγχου κάθε τύπου. Για παράδειγμα, ο πρώτος καταχωρητής κατάστασης είναι IIC1S και ο δεύτερος καταχωρητής κατάστασης είναι IIC2S.

11.2.8.1. Μητρώο ελέγχου IICC

Για τη σειρά MK AC. AW, Dx, EL, GB, GT, JM, LC, QE. Q.G. SG, SH, SL
Κανω ΕΓΓΡΑΦΗ Τρόπος Δ7 D6 D5 Δ4 D3 Δ2 Δ1 D0
IICC ΑΝΑΓΝΩΣΗ IICEN IICIE MST TX ΤΧΑΚ 0 0 0
Ρεκόρ RSTA
Επαναφορά 0 0 0 0 0 0 0 0
Περιγραφή bits:
Όνομα bit Περιγραφή Σύμβολο στη γλώσσα C
IICEN Bit ενεργοποίησης μονάδας I2C:
0 — Ο ελεγκτής I2C είναι απενεργοποιημένος.
1 - Ο ελεγκτής I2C είναι ενεργοποιημένος.
bIICEN
IICIE Bit ενεργοποίησης διακοπής μονάδας από το I2C:
0 - Οι διακοπές αιτήματος I2C είναι απενεργοποιημένες.
1 - Οι διακοπές αιτήματος I2C είναι ενεργοποιημένες.
bHCIE
MST Bit επιλογής τρόπου λειτουργίας ελεγκτή I2C:
0 - Ο ελεγκτής I2C λειτουργεί σε λειτουργία Slave.
1 - Ο ελεγκτής I2C λειτουργεί σε λειτουργία Master.
Όταν αυτό το bit αλλάζει από 0 σε 1, δημιουργείται μια κατάσταση έναρξης. Αντίθετα, όταν ένα bit αλλάζει από 1 σε 0, δημιουργείται μια συνθήκη Stop.
bMST
TX Bit επιλογής κατεύθυνσης μετάδοσης στη γραμμή δεδομένων SDA:
0 — η γραμμή λειτουργεί για είσοδο.
1 - η γραμμή λειτουργεί για έξοδο.
bTX
ΤΧΑΚ Bit επιβεβαίωσης σε λειτουργία λήψης:
0 - ένα bit επιβεβαίωσης δημιουργείται μετά τη λήψη ενός byte.
1 - δημιουργείται ένα μπιτ χωρίς επιβεβαίωση.
Αυτό το bit ελέγχει τη δημιουργία ενός bit επιβεβαίωσης μετά τη λήψη ενός byte δεδομένων, ανεξάρτητα από το αν είναι slave ή master.
bTXAK
RSTA Εάν η μονάδα I2C λειτουργεί σε κύρια λειτουργία, τότε η εγγραφή ενός 1 σε αυτό το bit προκαλεί την εκ νέου δημιουργία της κατάστασης Έναρξη - "Επανεκκίνηση". bRSTA

11.2.8.2. Μητρώο κατάστασης IICS

Για τις σειρές MK AC, AW, Dx, EL, GB, GT, JM, LC, QE, QG, SG, SH, SL
Κανω ΕΓΓΡΑΦΗ Τρόπος Δ7 D6 D5 Δ4 D3 Δ2 Δ1 D0
IICS ΑΝΑΓΝΩΣΗ TCF IAAS ΑΠΑΣΧΟΛΗΜΕΝΟΣ ARBL 0 SRW IICIF RXAK
Ρεκόρ
Επαναφορά 0 0 0 0 0 0 0 0
Περιγραφή bits:
Όνομα bit Περιγραφή Σύμβολο στη γλώσσα C
TCF bit ολοκλήρωσης ανταλλαγής. Ορίστε μετά την ολοκλήρωση της ανταλλαγής ενός byte:
0 — η ανταλλαγή δεν ολοκληρώθηκε.
1 - η ανταλλαγή ολοκληρώθηκε.
Η σημαία TCF διαγράφεται στο 0 όταν διαβάζεται ο καταχωρητής δεδομένων IICD (σε λειτουργία λήψης) ή όταν εγγράφεται ο καταχωρητής δεδομένων IICD (σε λειτουργία μετάδοσης).
bTCF
IAAS Σημαία διεύθυνσης σκλάβου. Ρυθμίστε εάν η συσκευή λειτουργεί σε λειτουργία υποτελούς λειτουργίας και η διεύθυνση που μεταδίδεται στο κύριο μήνυμα είναι ίση με τη δευτερεύουσα διεύθυνση, η οποία είναι αποθηκευμένη στον καταχωρητή διευθύνσεων IICA.
Η σημαία διαγράφεται κατά την εγγραφή στο μητρώο IICC.
bIAAS
ΑΠΑΣΧΟΛΗΜΕΝΟΣ Σημαία πολυάσχολης γραμμής. Αυτή η σημαία ορίζεται εάν η μονάδα I2C έχει αναγνωρίσει το bit έναρξης στη γραμμή. Η σημαία διαγράφεται όταν η μονάδα ανιχνεύσει ένα bit stop στη γραμμή.
0 — Το λεωφορείο I2C είναι δωρεάν.
1 - Το λεωφορείο I2C είναι απασχολημένο.
bUSY
ARBL Σημαία απώλειας διαιτησίας:
0 - καμία παραβίαση στη λειτουργία του λεωφορείου I2C.
1 – υπάρχει απώλεια διαιτησίας. Η μονάδα I2C πρέπει να περιμένει για λίγο και μετά να ξεκινήσει ξανά τη λειτουργία μεταφοράς.
BARBL
SRW Σκλάβος κατεύθυνσης μετάδοσης. Αυτό το bit υποδεικνύει την κατάσταση του R/W bit στο πεδίο διεύθυνσης:
0 - ο σκλάβος δέχεται. Ο αρχηγός μεταδίδει στον δούλο?
1 - ο σκλάβος μεταδίδει. Ο αρχηγός λαμβάνει από τον δούλο.
bSRW
IICIF Σημαία αιτημάτων διακοπής που δεν εξυπηρετούνται για τη μονάδα I2C. Ορίστε σε 1 εάν έχει οριστεί μία από τις σημαίες: TCF, IAAS ή ARBL.
0 - χωρίς διακοπές χωρίς συντήρηση.
1 - υπάρχουν διακοπές χωρίς συντήρηση.
Η σημαία επαναφέρεται γράφοντας 1 σε αυτήν.
bIICIF
RXAK Bit αναγνώρισης Master:
0—επιβεβαιωμένη λήψη δεδομένων με υποτελή.
1 — ο σκλάβος δεν επιβεβαίωσε τη λήψη δεδομένων.
Αυτό το bit αντικατοπτρίζει την κατάσταση του πεδίου ASK στο διάγραμμα χρονισμού της ανταλλαγής.
bRXAK

11.2.8.3. Μητρώο διεύθυνσης IICA

Κανω ΕΓΓΡΑΦΗ Τρόπος Δ7 D6 D5 Δ4 D3 Δ2 Δ1 D0
IICA ΑΝΑΓΝΩΣΗ ADDR
Ρεκόρ
Επαναφορά 0 0 0 0 0 0 0 0

Αυτό το μητρώο αποθηκεύει τη δευτερεύουσα διεύθυνση 7-bit που έχει εκχωρήσει ο προγραμματιστής αυτή η συσκευήκατά την ανάπτυξη του συστήματος. Αυτή η διεύθυνση συγκρίνεται αυτόματα με τον κωδικό διεύθυνσης που έλαβε ο εξαρτημένος στο πεδίο διεύθυνσης στο δίαυλο I2C. Εάν οι διευθύνσεις ταιριάζουν, ορίζεται το bit IAAS στον καταχωρητή κατάστασης IICS.

11.2.8.4. Μητρώο IICF Baud Rate

Για τις σειρές MK AC, AW, Dx, EL, GB, GT, JM, LC, QE, QG, SG, SH, SL
Κανω ΕΓΓΡΑΦΗ Τρόπος Δ7 D6 D5 Δ4 D3 Δ2 Δ1 D0
IICF ΑΝΑΓΝΩΣΗ MULT ICR
Ρεκόρ
Επαναφορά 0 0 0 0 0 0 0 0
Περιγραφή bits:

Τιμές συντελεστών SCL_DIV και SDA_HV

ISR SCL_DIV SDA_HV ISR SCL_DIV SDA_HV
0x00 20 7 0x20 160 17
0x01 22 7 0x21 192 17
0x02 24 8 0x22 224 33
0x03 26 8 0x23 256 33
0x04 28 9 0x24 288 49
0x05 30 9 0x25 320 49
0x06 34 10 0x26 384 65
0x07 40 10 0x27 480 65
0x08 28 7 0x28 320 33
0x09 32 7 0x29 384 33
0x0A 36 9 0x2A 448 65
0x0B 40 9 0x2B 512 65
0x0C 44 11 0x2C 576 97
0x0D 48 11 0x2D 640 97
0x0E 56 13 0x2E 768 129
0x0F 68 13 0x2F 960 129
0x10 48 9 0x30 640 65
0x11 56 9 0x31 768 65
0x12 64 13 0x32 896 129
0x13 72 13 0x33 1024 129
0x14 80 17 0x34 1152 193
0x15 88 17 0x35 1280 193
0x16 104 21 0x36 1536 257
0x17 128 21 0x37 1920 257
0x18 80 9 0x38 1280 129
0x19 96 9 0x39 1536 129
0x1A 112 17 0x3A 1792 257
0x1B 128 17 0x3B 2048 257
0x1C 144 25 0x3C 2304 385
0x1D 160 25 0x3D 2560 385
0x1E 192 33 0x3E 3072 513
0x1F 240 33 0x3F 3840 513

Αυτός ο καταχωρητής αποθηκεύει πεδία δύο bit που καθορίζουν τις παραμέτρους ταχύτητας και χρονισμού της ανταλλαγής I2C. Η συχνότητα των σημάτων συγχρονισμού καθορίζεται από τον τύπο:

Ο χρόνος διευθέτησης δεδομένων SDA_hold_time στο δίαυλο I2C είναι το χρονικό διάστημα μεταξύ της στιγμής που το σήμα SCL τίθεται στο 0 και των δεδομένων στη γραμμή SDA αλλάζουν. Εκχωρήθηκε από την παράμετρο SDA_HV (SDA_Hold_Value) από τον πίνακα για τον παράγοντα ICR του καταχωρητή ρυθμού baud:

.

11.2.8.5. Μητρώο δεδομένων IICD

Για τις σειρές MK AC, AW, Dx, EL, GB, GT, JM, LC, QE, QG, SG, SH, SL
Κανω ΕΓΓΡΑΦΗ Τρόπος Δ7 D6 D5 Δ4 D3 Δ2 Δ1 D0
IICD ΑΝΑΓΝΩΣΗ ΔΕΔΟΜΕΝΑ I2C
Ρεκόρ
Επαναφορά 0 0 0 0 0 0 0 0

Εάν η μονάδα I2C λειτουργεί σε λειτουργία κύριας λειτουργίας, τότε μια λειτουργία εγγραφής σε αυτόν τον καταχωρητή εκκινεί την επικοινωνία I2C (αλλά μόνο εάν το bit κατεύθυνσης επικοινωνίας στον καταχωρητή ελέγχου IICC έχει ρυθμιστεί σωστά, δηλ. TX = 1). Το πρώτο byte μετά την κατάσταση έναρξης, το οποίο το πρόγραμμα γράφει στον καταχωρητή δεδομένων, ερμηνεύεται από τους slaves ως η διεύθυνση της συσκευής. Επομένως, το πρόγραμμα πρέπει να σχηματίζει σωστά τα περιεχόμενα του πρώτου byte. Η λειτουργία ανάγνωσης καταχωρητή επιστρέφει το τελευταίο byte που ελήφθη μέσω I2C. Η λειτουργία ανάγνωσης καταχωρητή ξεκινά επίσης την έναρξη λήψης του επόμενου byte, αλλά μόνο εάν το bit κατεύθυνσης επικοινωνίας στον καταχωρητή ελέγχου IICC έχει ρυθμιστεί σωστά, δηλ. στο TX = 0! Με TX = 1, μια λειτουργία ανάγνωσης καταχωρητή δεν θα προκαλέσει τη λήψη ενός νέου byte μέσω I2C από την υποτελή.

Εάν η μονάδα I2C λειτουργεί σε λειτουργία υποτελούς λειτουργίας, τότε τα δεδομένα που είναι γραμμένα σε αυτόν τον καταχωρητή θα μεταφερθούν στη γραμμή SDA του διαύλου I2C όταν η κύρια συσκευή εκτελεί έναν κύκλο λήψης από αυτήν την υποτελή. Η λειτουργία ανάγνωσης καταχωρητή επιστρέφει το τελευταίο byte που ελήφθη από το master.

11.2.8.6. Καταχωρητής ελέγχου IICC2

Για τις σειρές MK AC, Dx, EL, JM, QE, SG, SH, SL
Κανω ΕΓΓΡΑΦΗ Τρόπος Δ7 D6 D5 Δ4 D3 Δ2 Δ1 D0
IICC ΑΝΑΓΝΩΣΗ GCAEN ADEXT 0 0 0 μ.Χ.10 AD9 μ.Χ.8
Ρεκόρ
Επαναφορά 0 0 0 0 0 0 0 0

Πρώτα βήματα με τον μεταγλωττιστή STM32 και mikroC για αρχιτεκτονική ARM - Μέρος 4 - Σύνδεση LCD με βάση I2C, pcf8574 και HD4478

Θα ήθελα να αφιερώσω το επόμενο άρθρο στην εργασία με την κοινή διεπαφή i2c, η οποία χρησιμοποιείται συχνά σε διάφορα μικροκυκλώματα που συνδέονται με έναν μικροελεγκτή.

Το I2C είναι ένας δίαυλος που λειτουργεί σε δύο φυσικές συνδέσεις (επιπλέον του κοινού καλωδίου). Γράφονται πολλά για αυτό στο Διαδίκτυο· υπάρχουν καλά άρθρα στη Wikipedia. Επιπλέον, ο αλγόριθμος λειτουργίας του διαύλου περιγράφεται πολύ καθαρά. Εν ολίγοις, ο δίαυλος είναι ένας σύγχρονος δίαυλος δύο καλωδίων. Μέχρι και 127 συσκευές μπορούν να βρίσκονται στο λεωφορείο ταυτόχρονα (η διεύθυνση της συσκευής είναι 7-bit, θα επανέλθουμε σε αυτό αργότερα). Παρακάτω είναι ένα τυπικό διάγραμμα για τη σύνδεση συσκευών στο δίαυλο i2c, με το MK ως κύρια συσκευή.


Για το i2c, όλες οι συσκευές (τόσο οι κύριες όσο και οι υποτελείς) χρησιμοποιούν εξόδους ανοιχτής αποστράγγισης. Με απλά λόγια, μπορούν να προσελκύσουν το ελαστικό ΜΟΝΟ στο ΕΔΑΦΟΣ. Το υψηλό επίπεδο διαύλου εξασφαλίζεται από αντιστάσεις έλξης. Η τιμή αυτών των αντιστάσεων επιλέγεται συνήθως στην περιοχή από 4,7 έως 10 kOhm. Το i2c είναι αρκετά ευαίσθητο στις φυσικές γραμμές που συνδέουν συσκευές, επομένως εάν χρησιμοποιείται σύνδεση με μεγάλη χωρητικότητα (για παράδειγμα, ένα μακρύ λεπτό ή θωρακισμένο καλώδιο), η επίδραση αυτής της χωρητικότητας μπορεί να «θολώσει» τις άκρες του σήματος και να επηρεάσει κανονική λειτουργίαελαστικά. Όσο μικρότερη είναι η αντίσταση έλξης, τόσο λιγότερη επιρροή έχει αυτή η χωρητικότητα στα χαρακτηριστικά των άκρων του σήματος, αλλά τόσο ΜΕΓΑΛΥΤΕΡΟ είναι το ΦΟΡΤΙΟ στα τρανζίστορ εξόδου στις διεπαφές i2c. Η τιμή αυτών των αντιστάσεων επιλέγεται για κάθε συγκεκριμένη υλοποίηση, αλλά δεν πρέπει να είναι μικρότερη από 2,2 kOhms, διαφορετικά μπορείτε απλά να κάψετε τα τρανζίστορ εξόδου σε συσκευές που λειτουργούν με το δίαυλο.

Ο δίαυλος αποτελείται από δύο γραμμές: SDA (γραμμή δεδομένων) και SCL (σήμα ρολογιού). Ρολόγια της κύριας συσκευής διαύλου, συνήθως το ΜΚ μας. Όταν το SCL είναι υψηλό, οι πληροφορίες διαβάζονται από το δίαυλο δεδομένων. Η κατάσταση SDA μπορεί να αλλάξει μόνο όταν το σήμα ρολογιού είναι χαμηλό.. Όταν το SCL είναι υψηλό, το σήμα στο SDA αλλάζει κατά τη δημιουργία σημάτων ΑΡΧΗ (όταν το SCL είναι υψηλό το σήμα στο SDA αλλάζει από υψηλό σε χαμηλό) και ΝΑ ΣΤΑΜΑΤΗΣΕΙ - όταν το επίπεδο SCL είναι υψηλό, το σήμα στο SDA αλλάζει από χαμηλό σε υψηλό).

Ξεχωριστά, πρέπει να ειπωθεί ότι στο i2c η διεύθυνση καθορίζεται ως αριθμός 7-bit. 8 - το λιγότερο σημαντικό bit υποδεικνύει την κατεύθυνση μεταφοράς δεδομένων 0 - σημαίνει ότι ο slave θα μεταδίδει δεδομένα, 1 - λαμβάνει.. Εν συντομία, ο αλγόριθμος για την εργασία με το i2c είναι ο εξής:

  • Υψηλό επίπεδο σε SDA και SCL- Το λεωφορείο είναι δωρεάν, μπορείτε να αρχίσετε να εργάζεστε
  • Κύριοι ανελκυστήρες SCLσε 1 και αλλάζει κατάσταση Σ.Δ.Α.από το 1 έως το 0 - το έλκει στο έδαφος - σχηματίζεται ένα σήμα ΑΡΧΗ
  • Ο κύριος μεταδίδει μια υποτελή διεύθυνση 7-bit με ένα bit κατεύθυνσης (δεδομένα σε Σ.Δ.Α.εκτίθενται όταν SCLτραβιέται στο έδαφος και διαβάζεται από τον σκλάβο όταν απελευθερώνεται). Εάν ο σκλάβος δεν έχει χρόνο να «αρπάξει» το προηγούμενο bit, προσελκύει SCLστο έδαφος, καθιστώντας σαφές στον πλοίαρχο ότι η κατάσταση του διαύλου δεδομένων δεν χρειάζεται να αλλάξει: «Ακόμα διαβάζω το προηγούμενο». Αφού ο πλοίαρχος αφήσει το ελαστικό, ελέγχει την άφησε ο σκλάβος;.
  • Μετά τη μετάδοση 8 bit της διεύθυνσης, η κύρια μονάδα δημιουργεί τον 9ο κύκλο ρολογιού και απελευθερώνει το δίαυλο δεδομένων. Αν ο σκλάβος άκουγε τη διεύθυνσή του και τη δεχόταν, τότε αυτός θα πατήσει Σ.Δ.Α.στο έδαφος. Έτσι σχηματίζεται το σήμα ΠΑΡΑΚΑΛΩ- δεκτό, όλα είναι εντάξει. Εάν ο σκλάβος δεν καταλαβαίνει τίποτα, ή απλά δεν είναι εκεί, τότε δεν θα υπάρχει κανείς να πατήσει το ελαστικό. ο κύριος θα περιμένει ένα τάιμ άουτ και θα καταλάβει ότι δεν έγινε κατανοητός.
  • Μετά τη μετάδοση της διεύθυνσης, αν έχουμε ορίσει την κατεύθυνση από αφέντη σε σκλάβο(8 bit της διεύθυνσης είναι ίσα με 1), στη συνέχεια ο κύριος μεταδίδει τα δεδομένα στον εξαρτημένο, χωρίς να ξεχνάει να ελέγξει την παρουσία του ΠΑΡΑΚΑΛΩαπό το slave, περιμένοντας τη slave συσκευή να επεξεργαστεί τις εισερχόμενες πληροφορίες.
  • Όταν το master λαμβάνει δεδομένα από το slave, το ίδιο το master παράγει ένα σήμα ΠΑΡΑΚΑΛΩμετά τη λήψη κάθε byte, και ο slave ελέγχει την παρουσία του. Ο κύριος ενδέχεται να μην στείλει συγκεκριμένα ΠΑΡΑΚΑΛΩπριν στείλετε την εντολή ΝΑ ΣΤΑΜΑΤΗΣΕΙ, καθιστώντας συνήθως σαφές στον δούλο ότι δεν χρειάζεται να παράσχετε περισσότερα δεδομένα.
  • Εάν, μετά την αποστολή δεδομένων από τον κύριο (λειτουργία εγγραφής), είναι απαραίτητο να διαβάσετε δεδομένα από το slave, τότε ο κύριος παράγει ξανά το σήμα ΑΡΧΗ , στέλνοντας τη διεύθυνση υποτελούς υπηρεσίας με σημαία ανάγνωσης. (αν πριν από την εντολή ΑΡΧΗδεν μεταφέρθηκε ΝΑ ΣΤΑΜΑΤΗΣΕΙτότε σχηματίζεται ομάδα ΕΠΑΝΕΚΚΙΝΗΣΗ). Αυτό χρησιμοποιείται για την αλλαγή της κατεύθυνσης της επικοινωνίας master-slave. Για παράδειγμα, περνάμε τη διεύθυνση μητρώου στον εξαρτημένο και, στη συνέχεια, διαβάζουμε δεδομένα από αυτό.)
  • Μετά την ολοκλήρωση της εργασίας με το slave, ο κύριος παράγει ένα σήμα ΝΑ ΣΤΑΜΑΤΗΣΕΙ- σε υψηλό επίπεδο του σήματος ρολογιού, σχηματίζει μια μετάβαση διαύλου δεδομένων από το 0 στο 1.
Το STM 32 διαθέτει πομποδέκτες διαύλου i2c με εφαρμογή υλικού. Μπορεί να υπάρχουν 2 ή 3 τέτοιες μονάδες σε ένα MK. Για τη διαμόρφωση τους, χρησιμοποιούνται ειδικοί καταχωρητές, που περιγράφονται στην αναφορά για το MK που χρησιμοποιείται.

Στο MicroC, πριν χρησιμοποιήσετε το i2c (καθώς και οποιοδήποτε περιφερειακό), πρέπει να αρχικοποιηθεί σωστά. Για να το κάνουμε αυτό, χρησιμοποιούμε την ακόλουθη συνάρτηση (Initialization ως master):

I2Cn_Init_Advanced(unsigned long: I2C_ClockSpeed, const Module_Struct *module);

  • n- αριθμός της μονάδας που χρησιμοποιείται, για παράδειγμα I2C1ή I2C2.
  • I2C_ClockSpeed- Ταχύτητα λεωφορείου, 100000 (100 kbs, τυπική λειτουργία) ή 400000 (400 kbs, γρήγορη λειτουργία). Το δεύτερο είναι 4 φορές πιο γρήγορο, αλλά δεν το υποστηρίζουν όλες οι συσκευές
  • *μονάδα μέτρησης- δείκτης σε μια περιφερειακή μονάδα, για παράδειγμα &_GPIO_MODULE_I2C1_PB67, μην το ξεχνάμε εδώ αυτό Βοηθός κώδικα (ctrl-space ) βοηθάει πολύ.
Αρχικά, ας ελέγξουμε αν το λεωφορείο είναι δωρεάν· υπάρχει μια λειτουργία για αυτό I2Cn_Is_Idle();επιστρέφοντας 1 εάν το λεωφορείο είναι δωρεάν και 0 εάν υπάρχει ανταλλαγή σε αυτό.

I2Cn_Start();
Οπου n- αριθμός της χρησιμοποιημένης μονάδας i2c του μικροελεγκτή μας. Η συνάρτηση θα επιστρέψει 0 εάν υπάρχει σφάλμα στο δίαυλο και 1 εάν όλα είναι εντάξει.

Για να μεταφέρουμε δεδομένα στο slave χρησιμοποιούμε τη συνάρτηση:

I2Cn_Write(ανυπόγραφη slave_address char, unsigned char *buf, unsigned long count, unsigned long END_mode);

  • n- αριθμός της μονάδας που χρησιμοποιείται
  • slave_address- 7-bit υποτελής διεύθυνση.
  • *μπουφ- ένας δείκτης στα δεδομένα μας - ένας πίνακας byte ή byte.
  • μετρώ- ο αριθμός των byte δεδομένων που μεταφέρθηκαν.
  • END_mode- τι πρέπει να κάνετε μετά τη μεταφορά δεδομένων στο slave, END_MODE_STOP - μετάδοση σήματος ΝΑ ΣΤΑΜΑΤΗΣΕΙ, ή END_MODE_RESTART Στείλε ξανά ΑΡΧΗ, δημιουργώντας ένα σήμα ΕΠΑΝΕΚΚΙΝΗΣΗκαι καθιστώντας σαφές στο τμήμα ότι η συνεδρία μαζί του δεν έχει τελειώσει και πλέον θα διαβαστούν δεδομένα από αυτόν.
Για να διαβάσετε δεδομένα από το slave, χρησιμοποιήστε τη συνάρτηση:

I2Cn_Read(char slave_address, char *ptrdata, unsigned long count, unsigned long END_mode);

  • n- αριθμός της μονάδας που χρησιμοποιείται
  • slave_address- 7-bit υποτελής διεύθυνση.
  • *μπουφ- ένας δείκτης σε μια μεταβλητή ή πίνακα στον οποίο λαμβάνουμε δεδομένα, πληκτρολογήστε char ή short int
  • μετρώ- αριθμός ληφθέντων byte δεδομένων.
  • END_mode- τι πρέπει να κάνετε μετά τη λήψη δεδομένων από τον δούλο - END_MODE_STOP - μετάδοση σήματος ΝΑ ΣΤΑΜΑΤΗΣΕΙ, ή END_MODE_RESTART στείλετε ένα σήμα ΕΠΑΝΕΚΚΙΝΗΣΗ.
Ας προσπαθήσουμε να συνδέσουμε κάτι στο MK μας. Αρχικά: το ευρέως διαδεδομένο μικροκύκλωμα PCF8574(A), το οποίο είναι μια επέκταση των θυρών εισόδου/εξόδου που ελέγχονται μέσω του διαύλου i2c. Αυτό το τσιπ περιέχει μόνο έναν εσωτερικό καταχωρητή, που είναι η φυσική του θύρα εισόδου/εξόδου. Δηλαδή, αν της περάσετε ένα byte, θα εκτεθεί αμέσως στα συμπεράσματά της. Εάν μετρήσετε ένα byte από αυτό (Μετάδοση ΑΡΧΗδιεύθυνση με σημαία ανάγνωσης, σήμα ΕΠΑΝΑΛΗΨΗ,διαβάστε τα δεδομένα και τελικά δημιουργήστε ένα σήμα ΝΑ ΣΤΑΜΑΤΗΣΕΙ) τότε θα αντικατοπτρίζει τις λογικές καταστάσεις στις εξόδους του. Ας συνδέσουμε το μικροκύκλωμά μας σύμφωνα με το φύλλο δεδομένων:


Η διεύθυνση μικροκυκλώματος σχηματίζεται από την κατάσταση των ακίδων Α0, Α1, Α2. Για μικροκύκλωμα PCF8574η διεύθυνση θα είναι: 0100A0A1A2. (Για παράδειγμα, έχουμε A0, A1, A2 σε υψηλό επίπεδο, οπότε η διεύθυνση του μικροκυκλώματος μας θα είναι 0b0100 111 = 0x27). Για PCF8574A - 0111A0A1A2, που με το διάγραμμα σύνδεσής μας θα δώσει τη διεύθυνση 0b0111 111 = 0x3F. Εάν, ας πούμε, το A2 είναι συνδεδεμένο στη γείωση, τότε η διεύθυνση για PCF8574Aθα 0x3B. Συνολικά, 16 μικροκυκλώματα μπορούν να τοποθετηθούν ταυτόχρονα σε ένα δίαυλο i2c, 8 PCF8574A και PCF8574 το καθένα.

Ας προσπαθήσουμε να μεταφέρουμε κάτι, να αρχικοποιήσουμε το δίαυλο i2c και να μεταφέρουμε κάτι στο PCF8574 μας.

#define PCF8574A_ADDR 0x3F //Διεύθυνση του PCF8574 μας void I2C_PCF8574_WriteReg(unsigned char wData) ( I2C1_Start(); // Δημιουργία του σήματος START I2C1_Write(PCAMO,Trans,END_D,10,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1). 1 byte δεδομένων και δημιουργήστε το STOP σήμα) char PCF8574A_reg ; // τη μεταβλητή που γράφουμε στο PCF8574 void main () ( I2C1_Init_Advanced(400000, &_GPIO_MODULE_I2C1_PB67); // Έναρξη I2C delay_ms(25); // Περιμένετε λίγο PCF8574A_reg.b0. ανάβει λίγο το PCF8574A_reg.b0. = 1; // απενεργοποιήστε το δεύτερο LED ενώ (1) ( delay_ms(500); PCF8574A_reg.b0 = ~PCF8574A_reg.b0; PCF8574A_reg.b1 = ~PCF8574A_reg.b1; // αντιστρέψτε την κατάσταση των LEDs ; // μεταφορά δεδομένων στο PCF8574 μας ))
Μεταγλωττίζουμε και τρέχουμε το πρόγραμμά μας και βλέπουμε ότι τα LED μας αναβοσβήνουν εναλλάξ.
Συνέδεσα την κάθοδο των LED στο PCF8574 μας για κάποιο λόγο. Το θέμα είναι ότι όταν τροφοδοτείται ένα λογικό 0 στην έξοδο, το μικροκύκλωμα τραβάει ειλικρινά την έξοδό του στο έδαφος, αλλά όταν εφαρμόζεται ένα λογικό 1, το συνδέει στο + ρεύμα μέσω μιας πηγής ρεύματος 100 μΑ. Δηλαδή, δεν μπορείτε να πάρετε ένα "τίμιο" λογικό 1 στην έξοδο. Και δεν μπορείτε να ανάψετε ένα LED με 100 μΑ. Αυτό έγινε για να ρυθμιστεί η έξοδος PCF8574 στην είσοδο χωρίς πρόσθετους καταχωρητές. Απλώς γράφουμε στον καταχωρητή εξόδου 1 (θέτοντας ουσιαστικά τις καταστάσεις ακίδας σε Vdd) και μπορούμε απλώς να τον βραχυκυκλώνουμε στη γείωση. Η τρέχουσα πηγή δεν θα επιτρέψει στο στάδιο εξόδου της επέκτασης I/O μας να «καεί». Εάν το πόδι τραβηχτεί στο έδαφος, τότε το δυναμικό γείωσης είναι πάνω του και διαβάζεται το λογικό 0. Εάν το πόδι τραβηχτεί στο +, τότε διαβάζεται το λογικό 1. Από τη μία πλευρά, είναι απλό, αλλά από την άλλη, θα πρέπει πάντα να το θυμάστε αυτό όταν εργάζεστε με αυτά τα μικροκυκλώματα.


Ας προσπαθήσουμε να διαβάσουμε την κατάσταση των ακίδων του τσιπ επέκτασης μας.

#define PCF8574A_ADDR 0x3F //Διεύθυνση του PCF8574 μας void I2C_PCF8574_WriteReg(unsigned char wData) ( I2C1_Start(); // Δημιουργία του σήματος START I2C1_Write(PCAMO,Trans,END_FER) 1 byte δεδομένων και δημιουργήστε το STOP signal) void I2C_PCF8574_ReadReg (unsigned char rData) ( I2C1_Start(); // Δημιουργία του σήματος START I2C1_Read(PCF8574A_ADDR, &rData, 1, END_MODE_STOP); // Ανάγνωση 1 byte χαρακτήρων και το σύμβολο PCF 1 byte; //μεταβλητή που γράφουμε στο PCF8574 char PCF8574A_out; // η μεταβλητή που διαβάζουμε και PCF8574 char lad_state; //Η λυχνία LED μας είναι αναμμένη ή απενεργοποιημένη void main () ( I2C1_Init_Advanced(400000, &_GPIO_MODULE_I2C1_PB67); // Έναρξη I2C delay_ms(25); // Περιμένετε λίγο PCF8574A_reg.b0 = 0; //reg. 57b1 Η πρώτη LED 1; / / απενεργοποιήστε τη δεύτερη λυχνία LED PCF8574A_reg.b6 = 1; // Τραβήξτε τις ακίδες 6 και 7 στην τροφοδοσία. PCF8574A_reg.b7 = 1; ενώ (1) ( delay_ms(100); I2C_PCF8574_WriteReg (PCF8574A) στο PCF8574 I2C_PCF8574_READREG (PCF8574 A_OUT); // Διαβάστε από το PCF8574 Εάν το κουμπί είναι το PCF8574444. ενεργοποιήστε/απενεργοποιήστε το LED μας) εάν (~PCF8574A_out .b7) PCF8574A_reg.b1 = ~PCF8574A_reg.b1; // παρόμοιο για 2 κουμπιά και 2 LED ) )
Τώρα πατώντας τα κουμπιά ανάβουμε ή σβήνουμε το LED μας. Το μικροκύκλωμα έχει άλλη έξοδο INT. Ένας παλμός δημιουργείται σε αυτό κάθε φορά που αλλάζει η κατάσταση των ακίδων του διαστολέα I/O μας. Συνδέοντάς το στην είσοδο εξωτερικής διακοπής του MK μας (θα σας πω πώς να ρυθμίσετε τις εξωτερικές διακοπές και πώς να εργαστείτε με αυτές σε ένα από τα παρακάτω άρθρα).

Ας χρησιμοποιήσουμε την επέκταση θύρας μας για να συνδέσουμε μια οθόνη χαρακτήρων μέσω αυτής. Υπάρχουν πάρα πολλά από αυτά, αλλά σχεδόν όλα είναι κατασκευασμένα με βάση ένα τσιπ ελεγκτή HD44780και τους κλώνους του. Για παράδειγμα, χρησιμοποίησα μια οθόνη LCD2004.


Το φύλλο δεδομένων για αυτό και τον ελεγκτή HD44780 βρίσκονται εύκολα στο Διαδίκτυο. Ας συνδέσουμε την οθόνη μας στο PCF8574 και τη δική της, αντίστοιχα, στο STM32 μας.

HD44780χρησιμοποιεί μια παράλληλη περιφραγμένη διεπαφή. Τα δεδομένα μεταδίδονται με 8 (ανά κύκλο ρολογιού) ή 4 (ανά 2 κύκλους ρολογιού) παλμούς πύλης στον ακροδέκτη μι. (διαβάζεται από τον ελεγκτή οθόνης σε φθίνουσα άκρη, μετάβαση από το 1 στο 0). συμπέρασμα R.S.υποδεικνύει εάν στέλνουμε δεδομένα στην οθόνη μας ( RS = 1) (οι χαρακτήρες που πρέπει να εμφανίζει είναι στην πραγματικότητα κωδικοί ASCII) ή η εντολή ( RS = 0). RWυποδεικνύει την κατεύθυνση μεταφοράς, εγγραφής ή ανάγνωσης δεδομένων. Συνήθως γράφουμε δεδομένα στην οθόνη, οπότε ( RW=0). Η αντίσταση R6 ελέγχει την αντίθεση της οθόνης. Δεν μπορείτε απλώς να συνδέσετε την είσοδο ρύθμισης αντίθεσης στη γείωση ή την τροφοδοσία, διαφορετικά δεν θα δείτε τίποτα.. Το VT1 χρησιμοποιείται για την ενεργοποίηση και απενεργοποίηση του οπίσθιου φωτισμού της οθόνης σύμφωνα με τις εντολές MK. Το MicroC διαθέτει μια βιβλιοθήκη για εργασία με τέτοιες οθόνες μέσω παράλληλης διεπαφής, αλλά συνήθως είναι ακριβό να ξοδέψετε 8 πόδια σε μια οθόνη, επομένως χρησιμοποιώ σχεδόν πάντα το PCF8574 για να δουλέψω με τέτοιες οθόνες. (Αν ενδιαφέρεται κάποιος, θα γράψω ένα άρθρο σχετικά με την εργασία με οθόνες που βασίζονται σε HD44780 ενσωματωμένες στο MicroC μέσω παράλληλης διεπαφής.) Το πρωτόκολλο ανταλλαγής δεν είναι ιδιαίτερα περίπλοκο (θα χρησιμοποιήσουμε 4 γραμμές δεδομένων και θα μεταφέρουμε πληροφορίες σε 2 κύκλους ρολογιού). φαίνεται ξεκάθαρα από το ακόλουθο διάγραμμα χρονισμού:


Πριν μεταφέρουμε δεδομένα στην οθόνη μας, πρέπει να αρχικοποιηθούν περνώντας εντολές σέρβις. (περιγράφεται στο φύλλο δεδομένων, εδώ παρουσιάζουμε μόνο τα πιο χρησιμοποιημένα)

  • 0x28- επικοινωνία με την ένδειξη μέσω 4 γραμμών
  • 0x0C- ενεργοποιήστε την έξοδο εικόνας, απενεργοποιήστε την εμφάνιση δρομέα
  • 0x0E- ενεργοποίηση εξόδου εικόνας, ενεργοποίηση εμφάνισης δρομέα
  • 0x01- διαγράψτε την ένδειξη
  • 0x08- απενεργοποιήστε την έξοδο εικόνας
  • 0x06- μετά την εμφάνιση του συμβόλου, ο κέρσορας μετακινείται κατά 1 οικείο σημείο
Δεδομένου ότι θα χρειαστεί να εργαζόμαστε με αυτόν τον δείκτη αρκετά συχνά, θα δημιουργήσουμε μια βιβλιοθήκη plug-in "i2c_lcd.h" . Για το σκοπό αυτό στο Project Manager Αρχεία κεφαλίδας και επιλέξτε Προσθήκη νέου αρχείου . Ας δημιουργήσουμε το αρχείο κεφαλίδας μας.

#define PCF8574A_ADDR 0x3F //Διεύθυνση του PCF8574 μας #define DB4 b4 // Αντιστοιχία μεταξύ των ακίδων PCF8574 και του δείκτη #define DB5 b5 #define DB6 b6 #define DB7 b7 #define EN b3 bdefin #define BL b0 // έλεγχος οπίσθιου φωτισμού #define displenth 20 // αριθμός χαρακτήρων στη γραμμή της οθόνης μας στατικό ανυπόγραφο char BL_status; // μεταβλητή που αποθηκεύει την κατάσταση του οπίσθιου φωτισμού (on/off) void lcd_I2C_Init(void); // Οθόνη και συνάρτηση αρχικοποίησης PCF8574 void lcd_I2C_txt(char *pnt); // Εμφανίζει μια γραμμή κειμένου, η παράμετρος είναι δείκτης σε αυτήν τη γραμμή void lcd_I2C_int(int pnt); // Εμφανίζει την τιμή μιας ακέραιας μεταβλητής, η παράμετρος είναι η τιμή εξόδου void lcd_I2C_Goto(unsigned short row, unsigned short col); // μετακινεί τον κέρσορα στην καθορισμένη θέση, γραμμή παραμέτρων - γραμμή (από 1 έως 2 ή 4 ανάλογα με την οθόνη) και col - (από 1 έως displenth)) void lcd_I2C_cls(); // Καθαρίζει το κενό της οθόνης lcd_I2C_backlight (ανυπόγραφη σύντομη κατάσταση int). // Ενεργοποιεί (κατά τη μετάδοση 1 και απενεργοποιεί - κατά τη μετάδοση 0 τον οπίσθιο φωτισμό της οθόνης)
Τώρα ας περιγράψουμε τις λειτουργίες μας, και πάλι πάμε στο Project Managerκάντε δεξί κλικ στον φάκελο Πηγές και επιλέξτε Προσθήκη νέου αρχείου . Δημιουργήστε ένα αρχείο "i2c_lcd.с" .

#include "i2c_lcd.h" //include αρχείο κεφαλίδας char lcd_reg; // καταχωρητής προσωρινής αποθήκευσης για δεδομένα που αποστέλλονται στο PCF8574 void I2C_PCF8574_WriteReg(unsigned char wData) //λειτουργία για αποστολή δεδομένων μέσω i2c στο τσιπ PCF8574 ( I2C1_Start(); I2C1_Write(PCF81DE,END_DA) ΕΝΤΟΛΗ (χαρ com) / /συνάρτηση αποστολής εντολής στην οθόνη μας ( lcd_reg = 0; //γράψτε 0 στον προσωρινό καταχωρητή lcd_reg.BL = BL_status.b0; //ρυθμίστε την ακίδα του οπίσθιου φωτισμού σύμφωνα με την τιμή της μεταβλητής που αποθηκεύει τον οπίσθιο φωτισμό κατάσταση lcd_reg.DB4 = com.b4; // ορίστε τα 4 πιο σημαντικά bit της εντολής μας στο δίαυλο δεδομένων δείκτη lcd_reg.DB5 = com.b5; lcd_reg.DB6 = com.b6; lcd_reg.DB7 = com.b7; lcd_reg .EN = 1; //ρυθμίστε την έξοδο στροβοσκοπίου σε 1 I2C_PCF8574_WriteReg ( lcd_reg); //γράψτε στον καταχωρητή PCF8574, στέλνοντας πραγματικά δεδομένα στον δείκτη delay_us (300); //περιμένετε το χρονικό όριο λήξης lcd_reg.EN = 0; // επαναφέρετε τον παλμό στροβοσκοπίου στο 0, η ένδειξη διαβάζει τα δεδομένα I2C_PCF8574_WriteReg (lcd_reg); delay_us (300) ; lcd_reg = 0; lcd_reg.BL = BL_status.b0; lcd_reg.DB4 = το λιγότερο σημαντικό για το //sa.b; bits lcd_reg.DB5 = com.b1; lcd_reg.DB6 = com.b2; lcd_reg.DB7 = com.b3; lcd_reg.EN = 1; I2C_PCF8574_WriteReg(lcd_reg); delay_us(300); lcd_reg.EN = 0; I2C_PCF8574_WriteReg(lcd_reg); delay_us(300); ) void LCD_CHAR (unsigned char com) //αποστολή δεδομένων (κωδικός χαρακτήρων ASCII) στην ένδειξη ( lcd_reg = 0; lcd_reg.BL = BL_status.b0; lcd_reg.EN = 1; lcd_reg.RS = 1; //αποστολή χαρακτήρα διαφέρει από την αποστολή εντολών ορίζοντας το bit RS σε 1 lcd_reg.DB4 = com.b4; //ρυθμίστε τα 4 πιο σημαντικά bit στις εισόδους lcd_reg.DB5 = com.b5; lcd_reg.DB6 = com.b6; lcd_reg.DB7 = com.b7; I2C_PCF8574_WriteReg (lcd_reg) ; delay_us (300); lcd_reg.EN = 0; // επαναφέρετε τον παλμό στροβοσκοπίου στο 0, ο δείκτης διαβάζει τα δεδομένα I2C_PCF8574_WriteReg (lcdregl_0);_0; .BL = BL_status.b0, lcd_reg.EN = 1, lcd_reg.RS = 1, lcd_reg.DB4 = com.b0, //ρυθμίστε τα 4 λιγότερο σημαντικά bit στις εισόδους lcd_reg.DB5 = com.b1, lcd_reg.DB6 = com.b2; lcd_reg.DB7 = com.b3; I2C_PCF8574_WriteReg ( lcd_reg); delay_us (300); lcd_reg.EN = 0; I2C_PCF8574_WriteReg (lcd_reg); _Init_Advanced(400000, &_GPIO_MODULE_I2C1_PB67 ); //αρχικοποιήστε τη μονάδα I2c μας στο M K delay_ms(200); lcd_Command(0x28); // Εμφάνιση σε 4 bit ανά λειτουργία ρολογιού delay_ms (5); lcd_Command(0x08); //Απενεργοποίηση της εξόδου δεδομένων στην οθόνη delay_ms (5); lcd_Command(0x01); //Εκκαθάριση της εμφάνισης delay_ms (5); lcd_Command(0x06); //Ενεργοποίηση αυτόματης μετατόπισης κέρσορα μετά την εμφάνιση του συμβόλου delay_ms (5); lcd_Command(0x0C); //Ενεργοποίηση εμφάνισης πληροφοριών χωρίς εμφάνιση του δρομέα delay_ms (25); ) void lcd_I2C_txt(char *pnt) //Έξοδος μιας συμβολοσειράς χαρακτήρων στην οθόνη ( ανυπόγραφο σύντομο int i; //μεταβλητή ευρετηρίου προσωρινού πίνακα χαρακτήρων char tmp_str; //προσωρινός πίνακας χαρακτήρων, μήκος 1 μεγαλύτερο από το μήκος της οθόνης γραμμή, δεδομένου ότι η γραμμή πρέπει να τερματιστεί σiv με NULL ASCII χαρακτήρα 0x00 strncpy(tmp_str, pnt, diplenth); //αντιγράψτε όχι περισσότερους από τους χαρακτήρες diplenth της αρχικής συμβολοσειράς στην προσωρινή μας συμβολοσειρά για (i=0; i Τώρα ας συνδέσουμε τη βιβλιοθήκη που δημιουργήθηκε πρόσφατα στο αρχείο με την κύρια λειτουργία μας:

#include "i2c_lcd.h" //include αρχείο κεφαλίδας μας ανυπόγραφο int i; //προσωρινή μεταβλητή μετρητή void main() ( lcd_I2C_Init(); //αρχικοποίηση της οθόνης lcd_I2C_backlight (1); //ενεργοποίηση του οπίσθιου φωτισμού lcd_I2C_txt ("Hello habrahabr"); //εμφάνιση της γραμμής ενώ (1) (delay_ms( 1000) ; lcd_I2C_Goto (2,1); //μετάβαση στον χαρακτήρα 1 της γραμμής 2 lcd_i2c_int (i); //εμφάνιση της τιμής i++; //αύξηση του μετρητή ) )

Εάν όλα έχουν συναρμολογηθεί σωστά, τότε θα πρέπει να δούμε κείμενο στην ένδειξη και έναν μετρητή να αυξάνεται κάθε δευτερόλεπτο. Γενικά, τίποτα περίπλοκο :)

Στο επόμενο άρθρο θα συνεχίσουμε να κατανοούμε το πρωτόκολλο i2c και τις συσκευές που λειτουργούν με αυτό. Ας εξετάσουμε το ενδεχόμενο να δουλέψουμε με τη μνήμη EEPROM 24XX και το επιταχυνσιόμετρο/γυροσκόπιο MPU6050.

Σήμερα υπάρχει ένας νέος επισκέπτης στο χειρουργικό μας τραπέζι, αυτό είναι ένα προϊόν Microchip, η επέκταση θύρας MCP23008-E. Αυτό το πράγμα έχει σκοπό (όπως υποδηλώνει το όνομα) να αυξήσει τον αριθμό των σκελών εισόδου/εξόδου του μικροελεγκτή εάν ξαφνικά γίνουν ανεπαρκή. Φυσικά, αν χρειαζόμαστε τα πόδια και τις εξόδους, τότε μπορούμε να το πάρουμε και να μην ανησυχούμε για αυτό. Εάν χρειάζεστε πόδια εισόδου, τότε υπάρχει μια λύση που βασίζεται στην αυστηρή λογική. Εάν χρειαζόμαστε και εισόδους και εξόδους και επίσης ένα ελεγχόμενο pull-up για τις εισόδους, τότε η επέκταση της θύρας είναι ίσως η πιο φυσιολογική λύση. Όσο για την τιμή της συσκευής, είναι πολύ μέτρια - περίπου ένα δολάριο. Σε αυτό το άρθρο θα προσπαθήσω να περιγράψω λεπτομερώς τον τρόπο ελέγχου αυτού του μικροκυκλώματος χρησιμοποιώντας τον μικροελεγκτή AVR.

Αρχικά, λίγα λόγια για τα χαρακτηριστικά:

  • 8 ανεξάρτητες ακίδες θύρας
  • Διεπαφή για επικοινωνία με τον έξω κόσμο - I2C (συχνότητα έως 1,7 MHz)
  • Προσαρμόσιμο pull-up για εισόδους
  • Μπορεί να τραντάξει το πόδι του όταν αλλάξει η κατάσταση ορισμένων εισροών
  • Τρεις είσοδοι για τη ρύθμιση της διεύθυνσης του μικροκυκλώματος (μπορείτε να κρεμάσετε 8 συσκευές σε ένα δίαυλο)
  • Τάση λειτουργίας από 1,8 έως 5,5 βολτ
  • Χαμηλή κατανάλωση ρεύματος
  • Μεγάλη ποικιλία περιβλημάτων (PDIP/SOIC/SSOP/QFN)

Προτιμώ να χρησιμοποιώ τη διεπαφή I2C, με ελκύει με μικρό αριθμό καλωδίων :-) ωστόσο, εάν χρειάζεστε πολύ γρήγορη ταχύτητα (έως 10 MHz), τότε πρέπει να χρησιμοποιήσετε τη διεπαφή SPI που υπάρχει στο MCP23S08. Η διαφορά μεταξύ MCP23S08 και MCP23008, όπως καταλαβαίνω, είναι μόνο στη διεπαφή και στον αριθμό των σκελών για τη ρύθμιση της διεύθυνσης του τσιπ. Σε ποιον αρέσει κάτι πιο σύντομο; Το pinout του mikruhi βρίσκεται στο φύλλο δεδομένων, δεν είναι ενδιαφέρον με κανέναν τρόπο και δεν θα ληφθεί υπόψη εδώ. Επομένως, ας προχωρήσουμε αμέσως στο πώς να ξεκινήσετε να εργάζεστε με αυτήν τη συσκευή. Όλη η εργασία καταλήγει στη συγγραφή και ανάγνωση ορισμένων δεδομένων από τους καταχωρητές του μικροκυκλώματος. Προς μεγάλη μου χαρά, δεν υπήρχαν καθόλου πολλά μητρώα - μόνο έντεκα από αυτά. Η εγγραφή και η ανάγνωση δεδομένων από μητρώα είναι πολύ απλή, δημοσιεύστε σχετικά. Είναι αλήθεια ότι δεν μιλάμε για μητρώα, αλλά η αρχή είναι η ίδια. Τώρα το μόνο που μένει είναι να καταλάβουμε από ποιους καταχωρητές να διαβάσετε από τι και από ποιους καταχωρητές να γράψετε τι. Φυσικά, το φύλλο δεδομένων θα μας βοηθήσει σε αυτό. Από το φύλλο δεδομένων μαθαίνουμε ότι το μικροκύκλωμα έχει τους εξής καταχωρητές:

Μητρώο IODIR
Καθορίζει την κατεύθυνση προς την οποία ρέουν τα δεδομένα. Εάν το bit που αντιστοιχεί σε ένα συγκεκριμένο σκέλος έχει οριστεί σε ένα, τότε το σκέλος είναι μια είσοδος. Εάν επαναφέρετε το μηδέν, βγείτε. Εν ολίγοις, αυτός ο καταχωρητής είναι ανάλογος με το DDRx στο AVR (μόνο στο AVR 1 είναι έξοδος και 0 είναι είσοδος).

Μητρώο IPOL
Εάν έχει οριστεί ένα bit καταχωρητή, τότε η αντιστροφή εισόδου είναι ενεργοποιημένη για το αντίστοιχο σκέλος. Αυτό σημαίνει ότι εάν εφαρμόσετε ένα κούτσουρο στο πόδι. το μηδέν τότε από τον καταχωρητή GPIO θεωρείται ένα και το αντίστροφο. Η χρησιμότητα αυτής της δυνατότητας είναι πολύ αμφίβολη.

Εγγραφή GPINTEN
Κάθε bit αυτού του καταχωρητή αντιστοιχεί σε μια συγκεκριμένη ακίδα θύρας. Εάν το bit έχει οριστεί, τότε η αντίστοιχη θύρα που έχει διαμορφωθεί ως είσοδος μπορεί να προκαλέσει διακοπή. Αν γίνει επαναφορά του bit, τότε ό,τι και να κάνετε με το σκέλος της θύρας, δεν θα υπάρξει διακοπή. Οι συνθήκες διακοπής ορίζονται από τους ακόλουθους δύο καταχωρητές.

Μητρώο DEFVAL
Η τρέχουσα τιμή των ακίδων που έχουν διαμορφωθεί για είσοδο συγκρίνεται συνεχώς με αυτόν τον καταχωρητή. Εάν ξαφνικά η τρέχουσα τιμή αρχίσει να διαφέρει από αυτή που υπάρχει σε αυτόν τον καταχωρητή, τότε εμφανίζεται μια διακοπή. Με απλά λόγια, εάν το bit έχει ρυθμιστεί, η διακοπή θα συμβεί όταν το επίπεδο αλλάξει από υψηλό σε χαμηλό στο αντίστοιχο σκέλος. Εάν το bit διαγραφεί, η διακοπή εμφανίζεται σε μια ανερχόμενη άκρη.

Εγγραφή INTCON
Κάθε bit αυτού του καταχωρητή αντιστοιχεί σε μια συγκεκριμένη ακίδα θύρας. Εάν το bit είναι καθαρό, τότε οποιαδήποτε αλλαγή στο λογικό επίπεδο στο αντίθετο προκαλεί διακοπή. Εάν το bit έχει οριστεί, η εμφάνιση της διακοπής επηρεάζεται από τον καταχωρητή DEFVAL (διαφορετικά αγνοείται εντελώς).

Μητρώο IOCON
Αυτό είναι το μητρώο ρυθμίσεων. Αποτελείται από τέσσερα bit:
SEQOP— αυτόματη αύξηση διεύθυνσης στοιχείων ελέγχου bit. Εάν είναι εγκατεστημένο, η αυτόματη αύξηση είναι απενεργοποιημένη, διαφορετικά είναι ενεργοποιημένη. Αν το απενεργοποιήσουμε, μπορούμε να διαβάσουμε την τιμή του ίδιου καταχωρητή πολύ γρήγορα λόγω του ότι δεν χρειάζεται να μεταδίδουμε τη διεύθυνσή του κάθε φορά. Εάν πρέπει να διαβάσετε γρήγορα και τους 11 καταχωρητές με τη σειρά, τότε η αυτόματη αύξηση πρέπει να είναι ενεργοποιημένη. Κάθε φορά που διαβάζεται ένα byte από τον καταχωρητή, η ίδια η διεύθυνση θα αυξάνεται κατά ένα και δεν θα χρειάζεται να μεταδοθεί.
DISSLW— ποιος ξέρει τι είναι αυτό το κομμάτι. Όπως και να το στρίψω, όλα λειτουργούν ακόμα. Θα χαρώ αν κάποιος μου εξηγήσει.
HAEN— Bit ρύθμισης εξόδου INT. Εάν έχει ρυθμιστεί, η ακίδα διαμορφώνεται ως ανοιχτή αποστράγγιση, εάν το bit επαναρυθμιστεί, τότε το ενεργό επίπεδο στο σκέλος INT καθορίζει το bit INTPOL
INTPOL— καθορίζει το ενεργό επίπεδο στο σκέλος INT. Εάν έχει οριστεί, το ενεργό επίπεδο είναι ένα, διαφορετικά μηδέν.

Υπάρχει ακόμα λίγο HAENαλλά δεν χρησιμοποιείται σε αυτό το τσιπ (ενεργοποιεί/απενεργοποιεί τις ακίδες διεύθυνσης υλικού στο MCP23S08)

Εγγραφή GPPU
Ελέγχει το άνοιγμα εισόδου. Εάν το bit έχει ρυθμιστεί, τότε στην αντίστοιχη ακίδα θα εμφανιστεί ένα άνοιγμα προς την τροφοδοσία μέσω μιας αντίστασης 100 kOhm.

Εγγραφή INTF
Διακοπή καταχωρητή σημαίας. Εάν το bit έχει οριστεί, αυτό σημαίνει ότι το αντίστοιχο σκέλος θύρας προκάλεσε διακοπή. Φυσικά, οι διακοπές για τα απαιτούμενα σκέλη πρέπει να είναι ενεργοποιημένες στον καταχωρητή GPINTEN

Εγγραφή INTCAP
Όταν συμβεί μια διακοπή, ολόκληρη η θύρα διαβάζεται σε αυτόν τον καταχωρητή. Εάν υπάρχουν περισσότερες διακοπές μετά από αυτό, τότε τα περιεχόμενα αυτού του μητρώου δεν θα αντικατασταθούν από τη νέα τιμή μέχρι να το διαβάσουμε ή το GPIO.

Εγγραφή GPIO
Κατά την ανάγνωση δεδομένων από το μητρώο, διαβάζουμε τα λογικά επίπεδα στις ακίδες της θύρας. Κατά την καταγραφή δεδομένων, ορίζουμε λογικά επίπεδα. Κατά την εγγραφή σε αυτόν τον καταχωρητή, τα ίδια δεδομένα εγγράφονται αυτόματα στον καταχωρητή OLAT

Μητρώο OLAT
Γράφοντας δεδομένα σε αυτόν τον καταχωρητή, εξάγουμε τα δεδομένα στη θύρα. Αν διαβάσετε δεδομένα από εκεί, θα διαβάσετε τι γράφτηκε και όχι τι υπάρχει στην πραγματικότητα στις εισόδους της θύρας. Για την ανάγνωση εισόδων χρησιμοποιούμε μόνο GPIO.

Η περιγραφή των μητρώων, κατά τη γνώμη μου, είναι αρκετά φυσιολογική και δεν πρέπει να μπερδεύει κανέναν. Τώρα, για πλάκα, ας γράψουμε μια μικρή επίδειξη που θα ψηφίσει 4 κουμπιά που είναι συνδεδεμένα στην επέκταση της θύρας και, ανάλογα με την κατάστασή τους, θα ανάψει ή θα απενεργοποιήσει 4 αντίστοιχες λυχνίες LED που είναι συνδεδεμένες στην ίδια επέκταση. Το παράδειγμα θα είναι όσο το δυνατόν πιο απλό, χωρίς διακοπές. Απλώς διαβάζουμε συνεχώς την κατάσταση των κουμπιών και εμφανίζουμε αυτή την κατάσταση στα LED. Το διάγραμμα της συσκευής μας θα μοιάζει με αυτό:

Ο ακροδέκτης διακοπής δεν χρειάζεται να συνδεθεί, δεν τον χρειαζόμαστε εδώ, αλλά απαιτείται το pull-up για το πόδι επαναφοράς! Ξόδεψα πολύ χρόνο μέχρι να συνειδητοποιήσω ότι η επέκταση της θύρας μου επανέφερε περιοδικά λόγω έλλειψης σύσφιξης. Τώρα ας πάμε στον κώδικα. Φυσικά θα γράψουμε στο . Απλός κώδικας:

Πρόγραμμα rashiritel; const AdrR=%01000001; //Διεύθυνση του τσιπ με το bit ανάγνωσης const AdrW=%01000000; //Διεύθυνση του τσιπ με την εγγραφή bit var r:byte; ///Η διαδικασία εγγράφει δεδομένα από τη μεταβλητή Dat στον καταχωρητή στη διεύθυνση Adr Procedure WriteReg(Dat,Adr:byte); Ξεκινήστε TWI_Start(); TWI_Write(AdrW); TWI_Write(Adr); TWI_Write(Dat); TWI_Stop(); Τέλος; ///Η συνάρτηση επιστρέφει την τιμή καταχωρητή στη διεύθυνση Adr Συνάρτηση ReadReg(Adr:byte):byte; var a:byte; Ξεκινήστε TWI_Start(); TWI_Write(AdrW); TWI_Write(Adr); TWI_Start(); TWI_Write(AdrR); a:=TWI_Read(0); TWI_Stop(); αποτέλεσμα:=a; Τέλος; έναρξη TWI_INIT(200000); ///Εκκίνηση του i2c WriteReg(%00001111,0x00); //Τα χαμηλότερα 4 bit είναι είσοδοι και τα υπόλοιπα 4 bit είναι έξοδοι WriteReg(%00001111,0x06); //Επί pull-up για 4 εισόδους Ενώ TRUE do Begin r:=ReadReg(0x09); //Διαβάστε την κατάσταση των εισόδων r:= NOT r; //Είναι απαραίτητο να αντιστρέψετε τα bit, διαφορετικά τα LED θα ανάψουν όταν απελευθερωθεί το κουμπί r:= r shl 4; //Shift 4 bit προς τα αριστερά... WriteReg(r,0x0A); //Εμφάνιση της κατάστασης των κουμπιών τέλος. τέλος.

Δημοσιεύθηκε 26/10/2016

Στο προηγούμενο άρθρο, εξετάσαμε τη λειτουργία του STM32 με το δίαυλο I 2 C ως Master. Δηλαδή ήταν αρχηγός και ανέκρινε τον αισθητήρα. Τώρα ας κάνουμε το STM32 Slave και ας ανταποκριθούμε σε αιτήματα, δηλαδή, το ίδιο λειτουργεί ως αισθητήρας. Θα διαθέσουμε 255 byte μνήμης για καταχωρητές με διευθύνσεις από 0 έως 0xFF και θα επιτρέψουμε στον Master να τους γράψει/διαβάσει. Και για να μην είναι τόσο απλό το παράδειγμα, ας κάνουμε το STM32 μετατροπέα αναλογικού σε ψηφιακό με διεπαφή I 2 C. Το ADC θα επεξεργαστεί 8 κανάλια. Ο ελεγκτής θα δώσει τα αποτελέσματα των μετασχηματισμών στον Master κατά την ανάγνωση από καταχωρητές. Εφόσον το αποτέλεσμα της μετατροπής ADC είναι 12 bit, χρειαζόμαστε 2 καταχωρητές (2 bytes) για κάθε κανάλι ADC.

i2c_slave.hπεριέχει ρυθμίσεις:

I2CSLAVE_ADDR– διεύθυνση της συσκευής μας

ADC_ADDR_START– τη διεύθυνση έναρξης των μητρώων που είναι υπεύθυνα για τα αποτελέσματα των μετατροπών ADC.

Στο αρχείο i2c_slave.cμας ενδιαφέρουν περισσότερο οι λειτουργίες get_i2c1_ramΚαι set_i2c1_ram. Λειτουργία get_i2c1_ramείναι υπεύθυνος για την ανάγνωση δεδομένων από μητρώα. Επιστρέφει δεδομένα από την καθορισμένη διεύθυνση, η οποία δίνεται στον Master. Στην περίπτωσή μας, τα δεδομένα διαβάζονται από τον πίνακα i2c1_ram, αλλά εάν ο Master ζητήσει διευθύνσεις μητρώου από το εύρος που έχει εκχωρηθεί για τα αποτελέσματα ADC, τότε αποστέλλονται τα δεδομένα μετατροπής ADC.

get_i2c1_ram:

Uint8_t get_i2c1_ram(uint8_t adr) ( //δεδομένα ADC εάν ((ADC_ADDR_START<= adr) & (adr < ADC_ADDR_START + ADC_CHANNELS*2)) { return ADCBuffer; } else { // Other addresses return i2c1_ram; } }

Λειτουργία set_i2c1_ram– εγγράφει δεδομένα που λαμβάνονται από τον Master σε μητρώα με την καθορισμένη διεύθυνση. Στην περίπτωσή μας, τα δεδομένα απλώς γράφονται σε έναν πίνακα i2c1_ram. Αλλά αυτό είναι προαιρετικό. Μπορείτε, για παράδειγμα, να προσθέσετε μια επιταγή και, όταν ένας συγκεκριμένος αριθμός φτάσει σε μια συγκεκριμένη διεύθυνση, να εκτελέσετε ορισμένες ενέργειες. Με αυτόν τον τρόπο μπορείτε να στείλετε διαφορετικές εντολές στον μικροελεγκτή.

set_i2c1_ram:

Void set_i2c1_ram(uint8_t adr, uint8_t val) ( i2c1_ram = val; return; )

Η εκκίνηση είναι αρκετά απλή:

Int main(void) ( SetSysClockTo72(); ADC_DMA_init(); I2C1_Slave_init(); while(1) ( ) )

Αρχικά ορίζουμε τη μέγιστη συχνότητα λειτουργίας του ελεγκτή. Η μέγιστη ταχύτητα απαιτείται όταν πρέπει να αποφευχθούν τυχόν καθυστερήσεις στο δίαυλο I 2 C. Στη συνέχεια ξεκινάμε τη λειτουργία ADC χρησιμοποιώντας DMA. ΣΧΕΤΙΚΑ ΜΕ . ΣΧΕΤΙΚΑ ΜΕ . Και τέλος, αρχικοποιούμε το δίαυλο I 2 C ως Δούλος. Όπως μπορείτε να δείτε, τίποτα περίπλοκο.

Τώρα ας συνδέσουμε τη μονάδα STM32 στο Raspberry Pi. Ας συνδέσουμε ποτενσιόμετρα στα κανάλια ADC. Και θα διαβάσουμε δείκτες ADC από τον ελεγκτή μας. Μην ξεχνάτε ότι για να λειτουργήσει ο δίαυλος I 2 C, πρέπει να εγκαταστήσετε αντιστάσεις έλξης σε κάθε γραμμή του διαύλου.

Στην κονσόλα Raspberry, ας ελέγξουμε αν η συσκευή μας είναι ορατή στο δίαυλο I 2 C (σχετικά με αυτό):

I2cidentect -y 1

Όπως μπορείτε να δείτε, η διεύθυνση της συσκευής 0x27, αν και καθορίσαμε 0x4E. Όταν έχετε χρόνο, σκεφτείτε γιατί συνέβη αυτό.

Για να διαβάσετε από τους καταχωρητές της συσκευής I 2 C-Slave, εκτελέστε την εντολή:

I2cget -y 1 0x27 0x00

Οπου:
0x27– διεύθυνση συσκευής,
0x00– διεύθυνση μητρώου (0x00…0xFF).

Για να γράψετε στους καταχωρητές της συσκευής I 2 C-Slave, εκτελέστε την εντολή:

I2cset -y 1 0x27 0xA0 0xDD

De:
0x27– διεύθυνση συσκευής,
0xA0– διεύθυνση μητρώου
0xDD-Δεδομένα 8 bit (0x00…0xFF)

Η προηγούμενη εντολή έγραψε τον αριθμό 0xDD στον καταχωρητή 0xA0(μπορείτε να γράψετε στους πρώτους 16 καταχωρητές, αλλά δεν έχει νόημα, αλλά είναι δεσμευμένοι για το ADC). Τώρα ας διαβάσουμε:

I2cget -y 1 0x27 0xA0

Για να απλοποιήσω τη διαδικασία ανάγνωσης δεδομένων καναλιού ADC, έγραψα ένα σενάριο:

#!/usr/bin/env python εισαγωγή smbus εισαγωγή χρόνου bus = smbus.SMBus(1) διεύθυνση = 0x27 while (1): ADC = (); για i στην περιοχή (0, 8): LBS = bus.read_byte_data (διεύθυνση, 0x00+i*2) MBS = bus.read_byte_data(διεύθυνση, 0x00+i*2+1) ADC[i] = MBS*256 + LBS εκτύπωση ADC time.sleep(0.2)

Δημοσκοπεί και εμφανίζει τα αποτελέσματα και των 8 καναλιών ADC στην κονσόλα.

Με παρόμοιο τρόπο, μπορείτε να συνδυάσετε πολλούς μικροελεγκτές. Ένα από αυτά πρέπει να είναι Master(), το άλλο Slave.

Σου εύχομαι επιτυχία!




Μπλουζα