Κοινή χρήση τεχνολογίας

STM32-I2C

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Αυτό το περιεχόμενο βασίζεται σεJiangxie Technology STM32Συγκεντρώθηκε μετά από μελέτη βίντεο.

Κατάλογος άρθρων

1. Επικοινωνία I2C

1.1 Εισαγωγή στην επικοινωνία I2C

  • Το I2C (Inter IC Bus) είναι ένας γενικός δίαυλος δεδομένων που αναπτύχθηκε από τη Philips
  • Δύο γραμμές επικοινωνίας: Γραμμή σειριακού ρολογιού SCL (Serial Clock), γραμμή σειριακών δεδομένων SDA (Serial Data)
  • Σύγχρονη, ημι-αμφίδρομη, μονού άκρου, πολλαπλών συσκευών
  • Απάντηση με δεδομένα
  • Υποστηρίζει την τοποθέτηση πολλαπλών συσκευών στο δίαυλο (ένας κύριος και πολλαπλοί slaves, πολλαπλοί κύριοι και πολλαπλοί slaves)
    • Ένας κύριος, πολλαπλοί σκλάβοι: Ο μικροελεγκτής χρησιμεύει ως κεντρικός υπολογιστής και κυριαρχεί στη λειτουργία του διαύλου I2C Όλες οι εξωτερικές μονάδες που είναι τοποθετημένες στο δίαυλο I2C είναι υποτελείς χωρίς άδεια διαύλου I2C για την αποφυγή συγκρούσεων.
    • Multi-master και multi-slave: Οποιαδήποτε μονάδα στο λεωφορείο μπορεί ενεργά να πηδήξει και να λειτουργήσει ως κύριος. Όταν συμβαίνει μια σύγκρουση διαύλου, το πρωτόκολλο I2C θα διεξάγει διαιτησία.

image.png

1.2 Κύκλωμα υλικού

  • Το SCL όλων των συσκευών I2C είναι συνδεδεμένο μαζί και το SDA είναι συνδεδεμένο μαζί.
  • Τόσο το SCL όσο και το SDA της συσκευής πρέπει να ρυθμιστούν σε λειτουργία εξόδου ανοιχτής αποστράγγισης.
  • Προσθέστε μια pull-up αντίσταση σε καθένα από τα SCL και SDA, η τιμή αντίστασης είναι γενικά περίπου 4,7KΩ

Φιγούρα 1Σχήμα 2
image.png

  • Ένας κύριος και πολλαπλοί εξαρτημένοι υπολογιστές: Η CPU είναι ένας μικροϋπολογιστής με ένα τσιπ, ως κύριος του διαύλου, ο κύριος έχει τον πλήρη έλεγχο της γραμμής SCL ανά πάσα στιγμή. Επιπλέον, στην κατάσταση αδράνειας, ο κεντρικός υπολογιστής μπορεί να ξεκινήσει ενεργά τον έλεγχο του SDA Μόνο όταν ο εξαρτημένος διακομιστής αποκρίνεται, ο κεντρικός υπολογιστής θα μεταφέρει τον έλεγχο του SDA στον εξαρτημένο υπολογιστή.
  • Το ελεγχόμενο IC είναι ένα slave τοποθετημένο στο δίαυλο I2C, το οποίο μπορεί να είναι αισθητήρας στάσης, OLED, μνήμη, μονάδα ρολογιού κ.λπ. Η ισχύς του εξαρτήματος είναι σχετικά μικρή Για τη γραμμή ρολογιού SCL, δεν επιτρέπεται να ελέγχει τη γραμμή SCL μόνο παθητικά. Για τη γραμμή δεδομένων SDA, η υποτελής δεν επιτρέπεται να εκκινήσει ενεργά τον έλεγχο της SDA. Μόνο αφού ο κύριος στείλει μια εντολή για ανάγνωση του slave ή όταν ο slave αποκριθεί, μπορεί ο slave να αποκτήσει για λίγο τον έλεγχο του SDA.
  • Εικόνα 2: SCL στα αριστερά και SDA στα δεξιά. Όλα τα δεδομένα μπορούν να εισαχθούν μέσω προσωρινής αποθήκευσης δεδομένων ή σκανδάλης Schmitt.
    • Επειδή η είσοδος δεν έχει καμία επίδραση στο κύκλωμα, οποιαδήποτε συσκευή μπορεί να έχει είσοδο ανά πάσα στιγμή.
    • Η έξοδος χρησιμοποιεί μια διαμόρφωση εξόδου ανοιχτής αποστράγγισης Όταν η έξοδος είναι χαμηλή, ο διακόπτης είναι ενεργοποιημένος και ο πείρος είναι απευθείας συνδεδεμένος με τη γείωση, κάτι που είναι ένα ισχυρό pull-down όταν η έξοδος είναι υψηλή, ο διακόπτης είναι απενεργοποιημένος δεν είναι συνδεδεμένο με τίποτα και είναι σε κατάσταση αιώρησης, έτσι ώστε όλες οι συσκευές να μπορούν να εξάγουν μόνο χαμηλή στάθμη αλλά όχι υψηλή στάθμη Προκειμένου να αποφευχθεί η αιώρηση που προκαλείται από την υψηλή στάθμη, το SCL και το SDA πρέπει να διαθέτουν εξωτερική αντίσταση έλξης. το λεωφορείο, μέσω μιας αντίστασης Τραβιέται σε υψηλό επίπεδο, επομένως είναι αδύναμο έλξη. Με αυτόν τον τρόπο, πρώτον, εξαλείφει τελείως το φαινόμενο του βραχυκυκλώματος και εξασφαλίζει την ασφάλεια του κυκλώματος, δεύτερον, αποφεύγει τη συχνή εναλλαγή των τρόπων ακίδων. Στη λειτουργία ανοιχτής αποστράγγισης, η έξοδος υψηλής στάθμης ισοδυναμεί με την αποσύνδεση της ακίδας, ώστε να μπορείτε να εξάγετε απευθείας ένα υψηλό επίπεδο πριν από την είσοδο. Τρίτον, αυτή η λειτουργία έχει ένα φαινόμενο "ενσύρματο ΚΑΙ" Εφόσον μία ή περισσότερες συσκευές εξάγουν χαμηλό επίπεδο, ο δίαυλος είναι σε χαμηλό επίπεδο. . Επομένως, το I2C μπορεί να εκμεταλλευτεί αυτό το φαινόμενο για να εκτελέσει συγχρονισμό ρολογιού και διαιτησία διαύλου σε λειτουργία πολλαπλού κύριου. Έτσι, παρόλο που το SCL εδώ μπορεί να χρησιμοποιήσει έξοδο push-pull σε μία λειτουργία κύριας και πολλαπλών υποτελών, εξακολουθεί να χρησιμοποιεί τη λειτουργία εξόδου ανοιχτής αποστράγγισης συν pull-out.

1.3 Βασική μονάδα χρονισμού I2C

1.3.1 Συνθήκες έναρξης και συνθήκες λήξης

  • κατάσταση εκκίνησης: Κατά το υψηλό επίπεδο SCL, το SDA αλλάζει από υψηλό επίπεδο σε χαμηλό επίπεδο
  • Προϋπόθεση τερματισμού: Κατά τη διάρκεια του υψηλού επιπέδου SCL, το SDA αλλάζει από χαμηλό επίπεδο σε υψηλό επίπεδο

image.png

  • υπό αρχικές συνθήκες : Όταν ο δίαυλος I2C βρίσκεται σε κατάσταση αδράνειας, τόσο το SCL όσο και το SDA βρίσκονται σε κατάσταση υψηλού επιπέδου, δηλαδή, καμία συσκευή δεν αγγίζει το SCL και το SCL και το SDA έλκονται σε υψηλό επίπεδο από εξωτερικές αντιστάσεις έλξης και ο δίαυλος είναι σε ήσυχη κατάσταση. Όταν ο κεντρικός υπολογιστής χρειάζεται να στείλει και να λάβει δεδομένα, πρέπει πρώτα να σπάσει τη σιωπή του διαύλου και να δημιουργήσει μια συνθήκη εκκίνησης, δηλαδή το SCL να βρίσκεται σε υψηλό επίπεδο χωρίς να το αγγίξει και, στη συνέχεια, να τραβήξει το SDA προς τα κάτω για να δημιουργήσει μια πτώση. Όταν το slave καταγράψει το υψηλό επίπεδο SCL και το σήμα πτώσης του SDA, θα επαναρυθμιστεί και θα περιμένει την κλήση του master. Μετά την πτώση του SDA, ο κεντρικός υπολογιστής πρέπει να τραβήξει ξανά προς τα κάτω το SCL. Θα διασφαλιστεί αργότερα ότι, εκτός από τις συνθήκες έναρξης και διακοπής, το SCL κάθε διαδοχικής μονάδας ξεκινά με χαμηλό επίπεδο και τελειώνει με χαμηλό επίπεδο.
  • Στην κατάσταση τερματισμού : Το SCL αφήνει πρώτα και ριμπάουντ στο υψηλό επίπεδο, μετά το SDA αφήνει να πάει και αναπηδά στο υψηλό επίπεδο, δημιουργώντας ένα ανερχόμενο πλεονέκτημα, το οποίο ενεργοποιεί τη συνθήκη τερματισμού. Μετά την ταυτόχρονη συνθήκη τερματισμού, τόσο το SCL όσο και το SDA είναι υψηλά και επιστρέφουν στην αρχική κατάσταση ηρεμίας.
    Η έναρξη και η διακοπή δημιουργούνται από τον κεντρικό υπολογιστή και η υποτελής δεν επιτρέπεται να δημιουργήσει έναρξη και διακοπή. Επομένως, όταν το λεωφορείο είναι αδρανές, ο σκλάβος πρέπει πάντα να αφήνει τα χέρια του και δεν επιτρέπεται να πηδήξει έξω και να αγγίξει το λεωφορείο.

1.3.2 Στείλτε ένα byte

  • Στείλτε ένα byte: Κατά τη διάρκεια του χαμηλού επιπέδου του SCL, ο κεντρικός υπολογιστής τοποθετεί τα bit δεδομένων στη γραμμή SDA στη σειρά (υψηλό bit πρώτα) και στη συνέχεια απελευθερώνει το SCL Το slave θα διαβάσει τα bit δεδομένων κατά το υψηλό επίπεδο του SCL, επομένως το SDA δεν επιτρέπεται για να έχετε δεδομένα κατά τη διάρκεια του υψηλού επιπέδου SCL Όταν αλλάζουν τα δεδομένα, κυκλώστε την παραπάνω διαδικασία 8 φορές για να στείλετε ένα byte.

Ο κεντρικός υπολογιστής χαμηλού επιπέδου τοποθετεί δεδομένα και ο υποτελής υψηλού επιπέδου διαβάζει δεδομένα.
image.png
Μετά τη συνθήκη έναρξης, το πρώτο byte πρέπει επίσης να σταλεί από τον κεντρικό υπολογιστή. Όταν το SCL είναι χαμηλό, αν ο κεντρικός υπολογιστής θέλει να στείλει 0, τραβάει το SDA χαμηλά εάν θέλει να στείλει το 1, αφήνει να πάει και το SDA επανέρχεται σε υψηλό επίπεδο. Κατά τη διάρκεια του χαμηλού επιπέδου του SCL, το επίπεδο του SDA επιτρέπεται να αλλάξει Μετά την τοποθέτηση των δεδομένων, ο κεντρικός υπολογιστής απελευθερώνει τη γραμμή του ρολογιού και το SCL επανέρχεται στο υψηλό επίπεδο. Κατά τη διάρκεια του υψηλού επιπέδου, είναι η ώρα που ο slave διαβάζει SDA, επομένως κατά το υψηλό επίπεδο, το SDA δεν επιτρέπεται να αλλάξει. Αφού το SCL βρίσκεται σε υψηλό επίπεδο, η υποτελής πρέπει να διαβάσει το SDA όσο το δυνατόν πιο γρήγορα. Επειδή το ρολόι ελέγχεται από τον κύριο, το slave δεν γνωρίζει πότε συμβαίνει η πτώση της ακμής, επομένως ο slave θα διαβάσει τα δεδομένα στην ανερχόμενη άκρη του SCL. Αφού ο κεντρικός υπολογιστής αφήσει το SCL για κάποιο χρονικό διάστημα, μπορεί να συνεχίσει να τραβάει το SCL χαμηλά και να μεταδίδει το επόμενο bit. Ο κεντρικός υπολογιστής πρέπει επίσης να τοποθετήσει δεδομένα στο SDA το συντομότερο δυνατό μετά την πτώση του SCL. Αλλά ο κεντρικός υπολογιστής έχει τον έλεγχο του ρολογιού, επομένως χρειάζεται μόνο να τοποθετήσει δεδομένα στο SDA οποιαδήποτε στιγμή όταν το χαμηλό επίπεδο είναι χαμηλό. Μετά την απελευθέρωση των δεδομένων, ο κεντρικός υπολογιστής απελευθερώνει ξανά το SCL, το SCL είναι υψηλό και το slave διαβάζει αυτό το bit. Επαναλάβετε αυτή τη διαδικασία: ο κεντρικός υπολογιστής τραβάει το SCL χαμηλά, τοποθετεί τα δεδομένα στο SDA, ο κεντρικός υπολογιστής απελευθερώνει το SCL και ο slave διαβάζει δεδομένα SDA. Κάτω από το συγχρονισμό του SCL, ο κύριος εκπέμπει και το slave λαμβάνει διαδοχικά Μετά από 8 κύκλους, αποστέλλονται δεδομένα 8 bit, που είναι ένα byte.
Δεδομένου ότι είναι πρώτα bit υψηλής τάξης, το πρώτο bit είναι το υψηλότερο bit B7 ενός byte και το χαμηλότερο bit B0 αποστέλλεται τελευταίο.

1.3.3 Λήψη byte

  • λάβετε ένα byte: Κατά τη διάρκεια του χαμηλού επιπέδου SCL, η υποτελής μονάδα τοποθετεί τα bit δεδομένων στη γραμμή SDA στη σειρά (υψηλό bit πρώτα) και στη συνέχεια απελευθερώνει το SCL Ο κεντρικός υπολογιστής θα διαβάσει τα bit δεδομένων κατά τη διάρκεια του υψηλού επιπέδου SCL, επομένως το SDA δεν επιτρέπεται για να έχετε δεδομένα κατά τη διάρκεια του υψηλού επιπέδου SCL Όταν αλλάζουν τα δεδομένα, κυκλώστε την παραπάνω διαδικασία 8 φορές για να λάβετε ένα byte (ο κεντρικός υπολογιστής πρέπει να απελευθερώσει το SDA πριν λάβει).

Το slave χαμηλού επιπέδου βάζει δεδομένα, ο κεντρικός υπολογιστής υψηλού επιπέδου διαβάζει δεδομένα
image.png
Γραμμή SDA: Η κύρια μονάδα πρέπει να απελευθερώσει το SDA πριν από τη λήψη, η υποτελής μονάδα αποκτά τον έλεγχο του SDA, θα τραβάει το SDA χαμηλά ριμπάουντ σε υψηλό επίπεδο. Το χαμηλό επίπεδο μετατρέπει δεδομένα, το υψηλό επίπεδο διαβάζει δεδομένα. Η συμπαγής γραμμή αντιπροσωπεύει το επίπεδο που ελέγχεται από τον κύριο και η διακεκομμένη γραμμή αντιπροσωπεύει το επίπεδο που ελέγχεται από τον υποτελή. Το SCL ελέγχεται από τον κεντρικό υπολογιστή καθ' όλη τη διάρκεια της διαδικασίας και ο κεντρικός υπολογιστής SDA πρέπει να απελευθερωθεί πριν από την παραλαβή και να παραδοθεί στον slave για έλεγχο. Επειδή το ρολόι SCL ελέγχεται από τον κεντρικό υπολογιστή, η μετατροπή δεδομένων του slave πραγματοποιείται βασικά στην πτώση του SCL και ο κεντρικός υπολογιστής μπορεί να διαβάσει οποιαδήποτε στιγμή όταν το SCL είναι υψηλό.

1.3.4 Αποστολή απάντησης και λήψη απάντησης

  • Αποστολή απάντησης: Μετά τη λήψη ενός byte, ο κεντρικός υπολογιστής στέλνει ένα bit δεδομένων στο επόμενο ρολόι.
  • λάβετε απάντηση: Αφού ο κεντρικός υπολογιστής στείλει ένα byte, λαμβάνει ένα bit δεδομένων στο επόμενο ρολόι για να προσδιορίσει εάν το slave ανταποκρίνεται.

image.png
Δηλαδή, μετά την κλήση του χρονισμού αποστολής ενός byte, θα πρέπει να ακολουθείται από το χρονοδιάγραμμα κλήσης της απόκρισης λήψης, που χρησιμοποιείται για να προσδιοριστεί εάν ο slave έχει λάβει τα δεδομένα που μόλις του δόθηκαν. Εάν το λάβετε το slave, τότε στο bit απόκρισης, όταν το master απελευθερώσει το SDA, το slave θα πρέπει να τραβήξει αμέσως το SDA προς τα κάτω και, στη συνέχεια, κατά τη διάρκεια του υψηλού επιπέδου SCL, ο κεντρικός υπολογιστής διαβάζει το bit απόκρισης. Εάν το bit απόκρισης είναι 0, σημαίνει ότι το slave το έχει όντως λάβει.
Όταν λαμβάνετε ένα byte, πρέπει να καλέσετε την απάντηση αποστολής. Ο σκοπός της αποστολής μιας απάντησης είναι να πείτε στον δούλο εάν θέλετε να συνεχίσετε την αποστολή. Εάν η εξαρτημένη μηχανή λάβει μια απάντηση από την κύρια μηχανή μετά την αποστολή ενός κομματιού δεδομένων, η υποτελής μηχανή θα συνεχίσει να στέλνει εάν η εξαρτημένη μηχανή δεν λάβει απάντηση από την κύρια μηχανή, η υποτελής μηχανή θα σκεφτεί ότι ένα τμήμα δεδομένων έχει. έχει σταλεί, αλλά η κύρια μηχανή με αγνοεί.

1.4 Χρονισμός I2C

1.4.1 Καθορίστε τη διεύθυνση για εγγραφή

  • Καθορίστε τη διεύθυνση για εγγραφή
  • Για την καθορισμένη συσκευή (Slave Address), γράψτε τα καθορισμένα δεδομένα (Data) στην καθορισμένη διεύθυνση (Reg Address) (δηλαδή τη διεύθυνση μητρώου της καθορισμένης συσκευής)

image.png
επεξεργάζομαι, διαδικασία:
(1) Συνθήκες εκκίνησης
(2) Χρόνος αποστολής ενός byte—0xD0 (υποτελής διεύθυνση (7bit) + εγγραφή (1bit)-0) (1101 0000)
(3) Λήψη απόκρισης: RA = 0 (λήψη απόκρισης από την υποτελή)
(4) Καθορισμένη διεύθυνση: 0x19 (0001 1001)
(5) Λήψη απόκρισης: RA = 0 (λήψη απόκρισης από την υποτελή)
(6) Γράψτε τα καθορισμένα δεδομένα: 0xAA (1010 1010)
(7) Λήψη απάντησης: RA = 0
(8) Stop bit P (συνθήκη τερματισμού)

  • Μετά τη συνθήκη έναρξης, πρέπει να είναι ο χρόνος αποστολής ενός byte. Το περιεχόμενο του byte πρέπει να είναι η υποτελής διεύθυνση + bit ανάγνωσης και εγγραφής 8 bit. Η αποστολή της υποτελούς διεύθυνσης είναι για τον προσδιορισμό του αντικειμένου επικοινωνίας και η αποστολή του bit ανάγνωσης και εγγραφής είναι για να επιβεβαιώσετε εάν θα γράψετε ή θα διαβάσετε στη συνέχεια. Τώρα ο κεντρικός υπολογιστής στέλνει ένα κομμάτι δεδομένων. Το περιεχόμενο του byte μετατρέπεται σε δεκαεξαδικό. Το μπιτ εγγραφής τελειώνει και το SCL τραβιέται χαμηλά Μετά από αυτό, ο κεντρικός υπολογιστής πρέπει να απελευθερώσει το SDA, ακολουθούμενο από το bit επιβεβαίωσης RA.
  • Το υψηλό επίπεδο μετά το τέλος του bit απόκρισης RA δημιουργείται από το slave που απελευθερώνει τον έλεγχο του SDA Επειδή ο slave θέλει να ανταλλάξει δεδομένα το συντομότερο δυνατό στο χαμηλό επίπεδο του SDA και του SDA. η πτώση του SCL συνέβη σχεδόν ταυτόχρονα.
  • Αφού ολοκληρωθεί η απόκριση, εάν συνεχίσετε να στέλνετε ένα byte, το δεύτερο byte μπορεί να σταλεί στο εσωτερικό της καθορισμένης συσκευής. Γενικά, το δεύτερο byte μπορεί να είναι μια διεύθυνση μητρώου ή μια λέξη ελέγχου εντολών, κ.λπ., και το τρίτο byte είναι το περιεχόμενο που θέλει να γράψει ο κεντρικός υπολογιστής στη διεύθυνση καταχωρητή (δεύτερο byte).
  • Το P είναι το bit διακοπής.

Ο σκοπός αυτού του πλαισίου δεδομένων είναι: για τη συσκευή που καθορίζει την υποτελή διεύθυνση 1101000, γράψτε τα δεδομένα 0xAA στον εσωτερικό της καταχωρητή στη διεύθυνση 0x19.
0 σημαίνει: ο κεντρικός υπολογιστής θα εκτελέσει μια λειτουργία εγγραφής στον επόμενο χρονισμό.
1 σημαίνει: ο κεντρικός υπολογιστής θα εκτελέσει μια λειτουργία ανάγνωσης στην επόμενη ακολουθία χρονισμού.

1.4.2 Ανάγνωση τρέχουσας διεύθυνσης

  • Διαβάστηκε η τρέχουσα διεύθυνση
  • Για την καθορισμένη συσκευή (Slave Address), διαβάστε τα υποτελή δεδομένα (Data) στη διεύθυνση που υποδεικνύεται από τον τρέχοντα δείκτη διεύθυνσης.

image.png
επεξεργάζομαι, διαδικασία:
(1) Συνθήκες εκκίνησης
(2) Χρόνος αποστολής ενός byte—0xD1 (slave address (7bit) + read (1bit)-1) (1101 0001)
(3) Λήψη απόκρισης: RA = 0 (λήψη απόκρισης από την υποτελή)
(4) Ανάγνωση υποτελών δεδομένων: 0x0F (0000 1111)
(7) Αποστολή απάντησης: SA = 0
(8) Stop bit P (συνθήκη τερματισμού)

  • Το bit ανάγνωσης και εγγραφής είναι 1, υποδεικνύοντας ότι πρόκειται να εκτελεστεί η επόμενη λειτουργία ανάγνωσης. Αφού αποκριθεί η υποτελής μονάδα (RA=0), η κατεύθυνση μετάδοσης δεδομένων θα αντιστραφεί. Ο κύριος θέλει να παραδώσει τον έλεγχο του SDA στο slave και ο κύριος καλεί το χρόνο λήψης ενός byte για να εκτελέσει τη λειτουργία λήψης.
  • Στο δεύτερο byte, το slave λαμβάνει άδεια από τον master και μπορεί να γράψει στο SCL κατά τη διάρκεια του υψηλού επιπέδου του SCL 8 bit, λαμβάνεται ένα byte δεδομένων που αποστέλλεται από το slave, το οποίο είναι 0x0F. Ποιος καταχωρητής όμως του slave είναι 0x0F; Στον χρονισμό ανάγνωσης, το πρωτόκολλο I2C ορίζει ότι όταν ο κεντρικός υπολογιστής διευθυνσιοδοτεί, μόλις η σημαία ανάγνωσης και εγγραφής οριστεί σε 1. Το επόμενο byte θα αλλάξει αμέσως σε χρονισμό ανάγνωσης. Επομένως, ο κεντρικός υπολογιστής θα αρχίσει να λαμβάνει πριν προλάβει να καθορίσει ποιο μητρώο θέλει να διαβάσει, επομένως δεν υπάρχει σύνδεσμος για να καθορίσετε τη διεύθυνση εδώ. Στη δευτερεύουσα μηχανή, όλοι οι καταχωρητές εκχωρούνται σε μια γραμμική περιοχή και θα υπάρχει μια ξεχωριστή μεταβλητή δείκτη που υποδεικνύει έναν από τους καταχωρητές Μετά την ανάγνωση ενός byte, ο δείκτης θα αυξηθεί αυτόματα μία φορά και θα μετακινηθεί στην επόμενη θέση. Στη συνέχεια, κατά την κλήση του χρόνου ανάγνωσης της τρέχουσας διεύθυνσης, εάν ο κεντρικός υπολογιστής δεν καθορίσει ποια διεύθυνση θα διαβάσει, ο υποτελής θα επιστρέψει στον καταχωρητή που επισημαίνεται από το. τρέχουσα τιμή.

1.4.3 Ανάγνωση σε καθορισμένη διεύθυνση

  • Καθορίστε τη διεύθυνση προς ανάγνωση
  • Για την καθορισμένη συσκευή (Slave Address), κάτω από την καθορισμένη διεύθυνση (Reg Address), διαβάστε τα υποτελή δεδομένα (Data)

image.png
Ξεκινήστε πρώτα, μετά επαναλάβετε την έναρξη και μετά σταματήστε
επεξεργάζομαι, διαδικασία:
(1) Συνθήκες εκκίνησης
(2) Χρόνος αποστολής ενός byte—0xD0 (υποτελής διεύθυνση (7bit) + εγγραφή (1bit)-0) (1101 0000)
(3) Λήψη απόκρισης: RA = 0 (λήψη απόκρισης από την υποτελή)
(4) Καθορισμένη διεύθυνση: 0x19 (0001 1001)
(5) Λήψη απόκρισης: RA = 0 (λήψη απόκρισης από την υποτελή)
(6) Επαναλάβετε την αρχική συνθήκη
(7) Χρόνος αποστολής ενός byte—0xD1 (slave address (7bit) + read (1bit)-1) (1101 0001)
(8) Λήψη απάντησης: RA = 0
(9) Ανάγνωση υποτελών δεδομένων: 0xAA (1010 1010)
(10) Αποστολή απάντησης: SA = 0
(11) Stop bit P (συνθήκη τερματισμού)

  • Το πρώτο μέρος είναι να γράψετε στην καθορισμένη διεύθυνση, αλλά καθορίζεται μόνο η διεύθυνση και δεν υπάρχει χρόνος για να γράψετε το δεύτερο μέρος είναι να διαβάσετε την τρέχουσα διεύθυνση, επειδή η διεύθυνση έχει μόλις καθοριστεί, επομένως η τρέχουσα διεύθυνση είναι ανάγνωση ξανακάλεσε.
  • Η καθορισμένη υποτελής διεύθυνση είναι 1101000, η ​​σημαία ανάγνωσης-εγγραφής είναι 0, και η λειτουργία εγγραφής εκτελείται μετά την απόκριση του εξαρτήματος, γράφεται ένα άλλο byte (το δεύτερο byte) για να καθοριστεί η διεύθυνση δείκτης διεύθυνσης, δηλαδή, αφού η υποτελής μονάδα λάβει τα δεδομένα, ο δείκτης καταχωρητή της δείχνει στη θέση 0x19.
  • Το Sr είναι μια επαναλαμβανόμενη συνθήκη έναρξης, η οποία ισοδυναμεί με την έναρξη ενός νέου χρονισμού Επειδή η καθορισμένη σημαία ανάγνωσης και εγγραφής μπορεί να ακολουθεί μόνο το πρώτο byte της συνθήκης έναρξης, επομένως, εάν θέλετε να αλλάξετε την κατεύθυνση ανάγνωσης και εγγραφής, μπορείτε μόνο να έχετε. άλλη συνθήκη εκκίνησης.
  • Στη συνέχεια, μετά τη συνθήκη έναρξης, επαναδιευθυνθείτε και καθορίστε το bit σημαίας ανάγνωσης-εγγραφής Αυτή τη στιγμή, το bit σημαίας ανάγνωσης-εγγραφής είναι 1, υποδεικνύοντας ότι πρόκειται να διαβαστεί. Στη συνέχεια, ο κεντρικός υπολογιστής λαμβάνει ένα byte 0xAA στη διεύθυνση 0x19.

2. MPU6050

2.1 Εισαγωγή στο MPU6050

  • Το MPU6050 είναι ένας αισθητήρας στάσης 6 αξόνων που μπορεί να μετρήσει τις παραμέτρους της επιτάχυνσης και της γωνιακής ταχύτητας των αξόνων X, Y και Z του τσιπ Μέσω της σύντηξης δεδομένων, η γωνία στάσης (γωνία Euler) χρησιμοποιείται συχνά εξισορρόπηση οχημάτων, αεροσκαφών κ.λπ. που πρέπει να ανιχνεύσουν τον εαυτό τους
  • Επιταχυνσιόμετρο 3 αξόνων (Accelerometer): μετρά την επιτάχυνση των αξόνων X, Y και Z
  • Γυροσκοπικός αισθητήρας 3 αξόνων (Γυροσκόπιο): μετρά τη γωνιακή ταχύτητα των αξόνων X, Y και Z

image.png

  • Λαμβάνοντας ως παράδειγμα την άτρακτο του αεροσκάφους, η γωνία Euler είναι η γωνία μεταξύ της ατράκτου του αεροσκάφους και των αρχικών τριών αξόνων.
    • αεροπλάνοΗ μύτη του αεροσκάφους γέρνει προς τα κάτω ή προς τα πάνω, ονομάζεται η γωνία μεταξύ αυτού του άξοναΠίσσα
    • αεροπλάνοΗ άτρακτος κυλά αριστερά ή δεξιά, ονομάζεται η γωνία μεταξύ αυτού του άξοναΡολό
    • αεροπλάνοΔιατηρήστε το επίπεδο της ατράκτουΓυρίστε τη μύτη του αεροσκάφους προς τα αριστερά ή προς τα δεξιά, ονομάζεται η γωνία μεταξύ αυτού του άξοναΕκτρέπομαι της οδού
    • Η γωνία Euler αντιπροσωπεύει τη στάση του αεροσκάφους αυτή τη στιγμή, είτε έχει κλίση προς τα πάνω ή προς τα κάτω, είτε έχει κλίση προς τα αριστερά ή προς τα δεξιά.
  • Οι κοινοί αλγόριθμοι σύντηξης δεδομένων περιλαμβάνουν γενικά το συμπληρωματικό φιλτράρισμα, το φιλτράρισμα Kalman, κ.λπ., και τον υπολογισμό στάσης στην αδρανειακή πλοήγηση.
  • Επιταχυνσιόμετρο : Η διακεκομμένη γραμμή στη μέση είναι ο άξονας επαγωγής Στη μέση υπάρχει ένα μικρό ρυθμιστικό με μια συγκεκριμένη μάζα που μπορεί να γλιστρήσει αριστερά και δεξιά. Όταν το ρυθμιστικό κινείται, θα οδηγήσει το ποτενσιόμετρο σε αυτό για να κινηθεί. Αυτό το επιταχυνσιόμετρο είναι στην πραγματικότητα ένα δυναμόμετρο ελατηρίου. Υπάρχει ένα επιταχυνσιόμετρο σε κάθε έναν από τους άξονες X, Y και Z. Τα επιταχυνσιόμετρα έχουν στατική σταθερότητα αλλά όχι δυναμική σταθερότητα.
  • Γυροσκοπικός αισθητήρας : Στη μέση είναι ένας περιστρεφόμενος τροχός με μια ορισμένη μάζα Όταν ο περιστρεφόμενος τροχός περιστρέφεται με υψηλή ταχύτητα, σύμφωνα με την αρχή της διατήρησης της γωνιακής ορμής, ο περιστρεφόμενος τροχός έχει την τάση να διατηρεί την αρχική του γωνιακή ορμή κατεύθυνση του άξονα περιστροφής αμετάβλητη. Όταν η κατεύθυνση του εξωτερικού αντικειμένου περιστρέφεται, η κατεύθυνση του εσωτερικού άξονα περιστροφής δεν θα περιστρέφεται, γεγονός που θα δημιουργήσει μια γωνιακή απόκλιση στη σύνδεση του δακτυλίου ισορροπίας. Εάν βάλετε ένα περιστρεφόμενο ποτενσιόμετρο στη σύνδεση και μετρήσετε την τάση του ποτενσιόμετρου, μπορείτε να πάρετε τη γωνία περιστροφής. Το γυροσκόπιο θα πρέπει να μπορεί να λαμβάνει απευθείας τη γωνία, αλλά το γυροσκόπιο αυτού του MPU6050 δεν μπορεί να μετρήσει απευθείας τη γωνία, δηλαδή τη γωνιακή ταχύτητα του τσιπ που περιστρέφεται γύρω από τον άξονα Χ, τον άξονα Υ και τον άξονα Z. -άξονας. Το ολοκλήρωμα της γωνιακής ταχύτητας είναι η γωνία Ωστόσο, όταν το αντικείμενο είναι ακίνητο, η τιμή της γωνιακής ταχύτητας δεν μπορεί να επιστραφεί πλήρως στο μηδέν λόγω του θορύβου. που είναι η γωνία που προκύπτει με την ολοκλήρωση της γωνιακής ταχύτητας Δεν μπορεί να αντέξει τη δοκιμασία του χρόνου, αλλά αυτή η γωνία δεν αποτελεί πρόβλημα είτε είναι ακίνητη είτε κινούμενη, και δεν επηρεάζεται από την κίνηση του αντικειμένου. Τα γυροσκόπια έχουν δυναμική σταθερότητα, όχι στατική σταθερότητα.
  • Σύμφωνα με το επιταχυνσιόμετρο, το οποίο έχει στατική σταθερότητα αλλά δεν έχει δυναμική σταθερότητα, αλλά δεν έχει στατική ευστάθεια, ώστε να μπορούμε να μάθουμε ο ένας από τα δυνατά σημεία του άλλου και να συμπληρώσουμε τις αδυναμίες του άλλου , μπορούμε να ενσωματώσουμε και στατική και δυναμική σταθερότητα Η στάση είναι άβολη.

2.2 παράμετροι MPU6050

  • Το ADC 16 bit συλλέγει το αναλογικό σήμα του αισθητήρα, εύρος κβαντισμού: -32768~32767
  • Επιλογή πλήρους κλίμακας επιταχυνσιόμετρου: ±2, ±4, ±8, ±16 (g) (1g = 9,8m/s2)
  • Επιλογή πλήρους κλίμακας γυροσκοπίου: ±250, ±500, ±1000, ±2000 (°/sec, βαθμός/δευτερόλεπτο, μονάδα γωνιακής ταχύτητας, πόσες μοίρες περιστροφής ανά δευτερόλεπτο) (όσο μεγαλύτερη είναι η επιλογή πλήρους κλίμακας, τόσο ευρύτερη είναι η εύρος μέτρησης Όσο μικρότερο είναι το εύρος πλήρους κλίμακας, τόσο μεγαλύτερη θα είναι η ανάλυση της μέτρησης)
  • Ρυθμιζόμενο ψηφιακό χαμηλοπερατό φίλτρο: Ένας καταχωρητής μπορεί να διαμορφωθεί για να επιλέγει το χαμηλοπερατό φιλτράρισμα των δεδομένων εξόδου.
  • Ρυθμιζόμενη πηγή ρολογιού
  • Ρυθμιζόμενη διαίρεση συχνότητας δειγματοληψίας: Η πηγή ρολογιού μπορεί να διαιρεθεί με το διαιρέτη συχνότητας για να παρέχει ρολόγια για μετατροπή AD και άλλα εσωτερικά κυκλώματα. Με τον έλεγχο του συντελεστή διαίρεσης συχνότητας, μπορείτε να ελέγξετε την ταχύτητα της μετατροπής AD.
  • Διεύθυνση υποτελούς υπηρεσίας I2C: 1101000 (AD0=0) ή 1101001 (AD0=1)
    • Το 110 1000 μετατρέπεται σε δεκαεξαδικό, το οποίο είναι 0x68, επομένως κάποιοι λένε ότι η υποτελής διεύθυνση του MPU6050 είναι 0x68. Αλλά στην επικοινωνία I2C, τα υψηλά 7 bit του πρώτου byte είναι η υποτελής διεύθυνση και το χαμηλότερο bit είναι το bit ανάγνωσης και εγγραφής. Επομένως, εάν νομίζετε ότι το 0x68 είναι η υποτελής διεύθυνση, κατά την αποστολή του πρώτου byte, πρέπει πρώτα να αλλάξετε. 0x68 Μετατόπιση αριστερά κατά 1 bit (0x68 << 1), στη συνέχεια ανάγνωση και εγγραφή bit κατά bit ή προς τα επάνω, ανάγνωση 1 και εγγραφή 0.
    • Μια άλλη μέθοδος είναι η μετατόπιση των δεδομένων του 0x68 προς τα αριστερά κατά 1 bit (0x68 << 1) ως υποτελής διεύθυνση, η οποία είναι 0xD0, σε αυτήν την περίπτωση, η υποτελής διεύθυνση του MPU6050 είναι 0xD0. Αυτή τη στιγμή, κατά την αποστολή του πρώτου byte, εάν θέλετε να γράψετε, χρησιμοποιήστε απλώς 0xD0 ως πρώτο byte, χρησιμοποιήστε 0xD0 ή 0x01 (0xD0 | 0x01), δηλαδή 0xD1 . Αυτή η αναπαράσταση δεν απαιτεί λειτουργία μετατόπισης προς τα αριστερά, ή με άλλα λόγια, αυτή η αναπαράσταση ενσωματώνει τα bit ανάγνωσης και εγγραφής στη διεύθυνση εξαρτημένης λειτουργίας. 0xD0 είναι η διεύθυνση εγγραφής και 0xD1 είναι η διεύθυνση ανάγνωσης.

2.3 Κύκλωμα υλικού

image.png

καρφίτσαΛειτουργία
VCC, GNDπαροχή ηλεκτρικού ρεύματος
SCL, SDAΚαρφίτσα επικοινωνίας I2C
XCL, XDAΥποδοχή ακίδων επικοινωνίας I2C
μ.Χ.0Το χαμηλότερο bit της υποτελούς διεύθυνσης
INTΈξοδος σήματος διακοπής
  • LDO: γραμμικός ρυθμιστής τάσης χαμηλής πτώσης, ρυθμιστής τάσης 3,3 V.
  • SCL και SDA: Είναι ακροδέκτες επικοινωνίας I2C Η μονάδα έχει ενσωματωμένες αντιστάσεις έλξης 4,7K, επομένως κατά την καλωδίωση, απλώς συνδέστε το SDA και το SCL απευθείας στη θύρα GPIO .
  • XCL, XDA: Host I2C pins επικοινωνίας Αυτές οι δύο ακίδες έχουν σχεδιαστεί για να επεκτείνουν τις λειτουργίες του chip. Συνήθως χρησιμοποιείται για εξωτερικά μαγνητόμετρα ή βαρόμετρα Όταν αυτά τα τσιπ επέκτασης είναι συνδεδεμένα, η διεπαφή κεντρικού υπολογιστή του MPU6050 μπορεί να έχει άμεση πρόσβαση στα δεδομένα αυτών των τσιπ επέκτασης στο MPU6050 υπολογισμός στάσης.
    AD0 pin: Είναι το χαμηλότερο bit της εξαρτημένης διεύθυνσης, εάν είναι συνδεδεμένη σε χαμηλό επίπεδο, η δευτερεύουσα διεύθυνση 7 bit είναι 1101000, εάν είναι συνδεδεμένη σε υψηλό επίπεδο, η δευτερεύουσα διεύθυνση 7 bit είναι 1101001. Υπάρχει μια αντίσταση στο διάγραμμα κυκλώματος, η οποία είναι ασθενώς κατεβασμένη σε χαμηλή στάθμη από προεπιλογή, οπότε αν η ακίδα αφεθεί να επιπλέει, είναι χαμηλή στάθμη Εάν θέλετε να τη συνδέσετε σε υψηλή στάθμη, μπορείτε να οδηγήσετε απευθείας το AD0 στο VCC και τραβήξτε το δυνατά σε υψηλό επίπεδο.
  • INT: Διακοπή της ακίδας εξόδου Μπορείτε να διαμορφώσετε ορισμένα συμβάντα μέσα στο τσιπ ώστε να ενεργοποιούν την έξοδο της ακίδας διακοπής, όπως είναι τα δεδομένα ετοιμότητας, το σφάλμα κεντρικού υπολογιστή I2C, κ.λπ.
  • Το τσιπ έχει επίσης ενσωματωμένο: ανίχνευση ελεύθερης πτώσης, ανίχνευση κίνησης, ανίχνευση μηδενικής κίνησης κ.λπ. Αυτά τα σήματα μπορούν να ενεργοποιήσουν τον ακροδέκτη INT για να δημιουργήσουν μια μετάβαση επιπέδου και τα σήματα διακοπής μπορούν να διαμορφωθούν εάν είναι απαραίτητο.
  • Το τροφοδοτικό του τσιπ MPU6050 είναι 2.375-3.46V, το οποίο είναι μια συσκευή τροφοδοσίας 3.3V και δεν μπορεί να συνδεθεί απευθείας σε 5V. Επομένως, προστίθεται ένας ρυθμιστής τάσης 3,3 V και η τάση του ακροδέκτη εισόδου VCC_5V μπορεί να είναι μεταξύ 3,3 V και 5 V, στη συνέχεια, ο ρυθμιστής τάσης 3,3 V εξάγει σταθερή τάση 3,3 V για να τροφοδοτήσει το τσιπ , Η ενδεικτική λυχνία λειτουργίας θα ανάψει.

2.4 Μπλοκ διάγραμμα MPU6050

image.png

  • Το CLKIN και το CLKOUT είναι ακίδες εισόδου ρολογιού και ακροδέκτες εξόδου ρολογιού, αλλά γενικά χρησιμοποιούμε το εσωτερικό ρολόι.
  • Το γκρι μέρος: είναι ο αισθητήρας μέσα στο τσιπ, το επιταχυνσιόμετρο στον άξονα XYZ και το γυροσκόπιο στον άξονα XYZ.
  • Υπάρχει επίσης ένας ενσωματωμένος αισθητήρας θερμοκρασίας που μπορεί να χρησιμοποιηθεί για τη μέτρηση της θερμοκρασίας.
  • Αυτοί οι αισθητήρες είναι ουσιαστικά ισοδύναμοι με μεταβλητές αντιστάσεις Μετά τη διαίρεση της τάσης, εξάγουν μια αναλογική τάση και στη συνέχεια εκτελούν μετατροπή αναλογικού σε ψηφιακό μέσω του ADC. Αφού ολοκληρωθεί η μετατροπή, τα δεδομένα από αυτούς τους αισθητήρες τοποθετούνται ομοιόμορφα στα δεδομένα καταχωρητή, η οποία μπορεί να ληφθεί με την ανάγνωση του καταχωρητή δεδομένων Η τιμή που μετράται από τον αισθητήρα. Όλες οι μετατροπές σε αυτό το τσιπ είναι πλήρως αυτοματοποιημένες.
  • Κάθε αισθητήρας έχει μια μονάδα αυτοελέγχου, η οποία χρησιμοποιείται για την επαλήθευση της ποιότητας του τσιπ Όταν ξεκινήσει ο αυτοέλεγχος, το τσιπ θα προσομοιώσει μια εξωτερική δύναμη που ασκείται στον αισθητήρα μεγαλύτερο από το συνηθισμένο. Διαδικασία αυτοδιαγνωστικού ελέγχου: Μπορείτε να ενεργοποιήσετε πρώτα τον αυτοέλεγχο, να διαβάσετε τα δεδομένα, μετά να ενεργοποιήσετε τον αυτοέλεγχο, να διαβάσετε τα δεδομένα, να αφαιρέσετε τα δύο δεδομένα και τα δεδομένα που προκύπτουν ονομάζονται απόκριση αυτοδιαγνωστικού ελέγχου. Για αυτήν την απόκριση αυτοελέγχου, το εγχειρίδιο δίνει ένα εύρος τιμών, αυτό σημαίνει ότι δεν υπάρχει πρόβλημα με το τσιπ.
  • Αντλία φόρτισης: Είναι αντλία φόρτισης ή αντλία φόρτισης.
  • Ο ακροδέκτης CPOUT απαιτεί εξωτερικό πυκνωτή.
  • Καταχωρητής κατάστασης διακοπής: μπορεί να ελέγξει ποια εσωτερικά συμβάντα εξάγονται στον ακροδέκτη διακοπής,
  • FIFO: First-in-first-out καταχωρητής, ο οποίος μπορεί να αποθηκεύσει προσωρινά τη ροή δεδομένων.
  • Καταχωρητής διαμόρφωσης: Μπορείτε να διαμορφώσετε διάφορα εσωτερικά κυκλώματα
  • Καταχωρητής αισθητήρα: Καταχωρητής δεδομένων, ο οποίος αποθηκεύει τα δεδομένα κάθε αισθητήρα.
  • Factory Calibrated: Αυτό σημαίνει ότι οι αισθητήρες στο εσωτερικό είναι βαθμονομημένοι.
  • Ψηφιακός επεξεργαστής κίνησης: DMP για συντομία, είναι ένας αλγόριθμος υλικού για τον υπολογισμό της στάσης που βρίσκεται μέσα στο τσιπ. Μπορεί να χρησιμοποιηθεί για τον υπολογισμό της στάσης με την επίσημη βιβλιοθήκη DMP.
  • FSYNC: Συγχρονισμός καρέ.

3. 10-1 Λογισμικό I2C ανάγνωσης και γραφής MPU6050

3.1 Σύνδεση υλικού

Μέσω της επικοινωνίας του λογισμικού I2C, διαβάστε και γράψτε τους καταχωρητές μέσα στο τσιπ MPU6050 Εγγράφοντας στον καταχωρητή διαμόρφωσης, μπορείτε να ρυθμίσετε τις παραμέτρους της μονάδας προσθήκης Διαβάζοντας το μητρώο δεδομένων Τα δεδομένα ανάγνωσης θα εμφανιστούν σε OLED, τα κορυφαία δεδομένα είναι ο αριθμός ID της συσκευής. Παρακάτω, τα τρία στα αριστερά είναι τα δεδομένα εξόδου του αισθητήρα επιτάχυνσης, τα οποία είναι η επιτάχυνση του άξονα X, του άξονα Y και του άξονα Z αντίστοιχα. που είναι η γωνιακή ταχύτητα του άξονα Χ, του άξονα Υ και του άξονα Ζ.
Το SCL συνδέεται με τον ακροδέκτη PB10 του STM32 και το SDA συνδέεται στον ακροδέκτη PB11. Δεδομένου ότι η αναστροφή επιπέδου λογισμικού εφαρμόζεται εδώ, δύο θύρες GPIO μπορούν να συνδεθούν κατά βούληση.

3.2 Αποτελέσματα λειτουργίας

IMG_20240406_155156.jpg

3.3 Ροή κώδικα

Το STM32 είναι ο κεντρικός υπολογιστής και το MPU6050 είναι το slave, το οποίο είναι μια λειτουργία master-slave.

  1. Δημιουργήστε τις μονάδες .c και .h του επιπέδου επικοινωνίας I2C
    1. Γράψτε την υποκείμενη προετοιμασία GPIO του I2C
    2. 6 βασικές μονάδες χρονισμού: έναρξη, τέλος, αποστολή byte, λήψη byte, αποστολή απάντησης, λήψη απάντησης
  2. Δημιουργήστε τις μονάδες .c και .h του MPU6050
    1. Βασισμένο στη μονάδα επικοινωνίας I2C, υλοποιεί την ανάγνωση στην καθορισμένη διεύθυνση, την εγγραφή στην καθορισμένη διεύθυνση, την εγγραφή καταχωρητών για τη διαμόρφωση του τσιπ και την ανάγνωση των καταχωρητών για τη λήψη δεδομένων αισθητήρα.
  3. κύρια.γ
    1. Καλέστε τη μονάδα MPU6050, αρχικοποιήστε, λάβετε τα δεδομένα και εμφανίστε τα δεδομένα

3.4 Κωδ

  1. Κωδικός I2C:
#include "stm32f10x.h"                  // Device header
#include "Delay.h"

void MyI2C_W_SCL(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_10,(BitAction)BitValue);
	Delay_us(10);
}

void MyI2C_W_SDA(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_11,(BitAction)BitValue);
	Delay_us(10);
}

uint8_t MyI2C_R_SDA(void)
{
	uint8_t BitValue;
	BitValue = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);
	Delay_us(10);
	return BitValue;
}

void MyI2C_Init(void)
{
/*
软件I2C初始化:
	1. 把SCL和SDA都初始化为开漏输出模式;
	2. 把SCL和SDA置高电平;
输入时,先输出1,再直接读取输入数据寄存器就行了;
初始化结束后,调用SetBits,把GPIOB的Pin_10和Pin_11都置高电平,
此时I2C总线处于空闲状态
*/	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
	
}

/*
起始条件:SCL高电平期间,SDA从高电平切换到低电平。
如果起始条件之前,SDA和SCL都已经是高电平了,那先释放哪一个是一样的效果。
但是这个Start还要兼容重复起始条件Sr,Sr最开始,SCL是低电平,SDA电平不敢确定,
所以为保险起见,在SCL低电平时,先确保释放SDA,再释放SCL。
这时SDA和SCL都是高电平,然后再拉低SDA、拉低SCL。
这样这个Start就可以兼容起始条件和重复起始条件了。
*/
void MyI2C_Start(void)
{
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
}

/*
终止条件:SCL高电平期间,SDA从低电平切换到高电平
如果Stop开始时,SCL和SDA都已经是低电平了,那就先释放SCL,再释放SDA。
但在这个时序单元开始时,SDA并不一定是低电平,所以为了确保之后释放
SDA能产生上升沿,要在时序单元开始时,先拉低SDA,然后再释放SCL、释放SDA。
*/
void MyI2C_Stop(void)// 终止条件
{
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}

/*
发送一个字节:发送一个字节时序开始时,SCL是低电平。
除了终止条件SCL以高电平结束,所有的单元都会保证SCL以低电平结束。
SCL低电平变换数据;高电平保持数据稳定。由于是高位先行,所以变换数据的时候,
按照先放最高位,再放次高位,...,最后最低位的顺序,依次把每一个字节的每一位放在SDA线上,
每放完一位后,执行释放SCL,拉低SCL的操作,驱动时钟运转。
程序:趁SCL低电平,先把Byte的最高位放在SDA线上,
*/

void MyI2C_SendByte(uint8_t Byte) // 发送一个字节
{
	uint8_t i;
	for (i = 0; i < 8; i ++)
	{
		MyI2C_W_SDA(Byte & (0x80 >> i));// 右移i位
	    MyI2C_W_SCL(1);
	    MyI2C_W_SCL(0);
	}
}

/*
接收一个字节:时序开始时,SCL低电平,此时从机需要把数据放到SDA上,
为了防止主机干扰从机写入数据,主机需要先释放SDA,释放SDA相当于切换为输入模式,
那在SCL低电平时,从机会把数据放到SDA上,如果从机想发1,就释放SDA,想发0,就拉低SDA,
主机释放SCL,在SCL高电平期间,读取SDA,再拉低SCL,低电平期间,从机就会把下一位数据放到SDA上,重复8次,
主机就能读到一个字节了。
SCL低电平变换数据,高电平读取数据,实际上是一种读写分离的操作,低电平时间定义为写的时间,高电平时间定义为读的时间,

*/
uint8_t MyI2C_ReceiveByte(void) // 接收一个字节
{
	uint8_t i, Byte = 0x00;
	MyI2C_W_SDA(1);
	for (i = 0; i < 8; i ++)
	{
		MyI2C_W_SCL(1); // 主机读取数据
	    if (MyI2C_R_SDA() == 1) // 如果if成立,接收的这一位为1,
	    {
		    Byte |= (0x80 >> i);   // 最高位置1
	    }
        MyI2C_W_SCL(0);	
	}
	return Byte;
}
/*
问题:反复读取SDA,for循环中又没写过SDA,那SDA读出来应该始终是一个值啊?
回答:I2C是在进行通信,通信是有从机的,当主机不断驱动SCL时钟时,
从机就有义务去改变SDA的电平,所以主机每次循环读取SDA的时候,
这个读取到的数据是从机控制的,这个数据也正是从机想要给我们发送的数据,
所以这个时序叫做接收一个字节。
*/

void MyI2C_SendAck(uint8_t AckBit) // 发送应答
{
	// 函数进来,SCL低电平,主机把AckBit放到SDA上,
	MyI2C_W_SDA(AckBit);
	MyI2C_W_SCL(1);  // 从机读取应答
	MyI2C_W_SCL(0);  // 进入下一个时序单元
	
}

uint8_t MyI2C_ReceiveAck(void) // 接收应答
{
	// 函数进来,SCL低电平,主机释放SDA,防止从机干扰
	uint8_t AckBit;
	MyI2C_W_SDA(1);  // 主机释放SDA
	MyI2C_W_SCL(1);  // SCL高电平,主机读取应答位
	AckBit = MyI2C_R_SDA(); 
	MyI2C_W_SCL(0);	 // SCL低电平,进入下一个时序单元
	return AckBit;
}

/*问题:在程序里,主机先把SDA置1了,然后再读取SDA,
这应答位肯定是1啊,
回答:第一,I2C的引脚是开漏输出+弱上拉的配置,主机输出1,
并不是强制SDA为高电平,而是释放SDA,
第二,I2C是在通信,主机释放了SDA,从机是有义务在此时把SDA再拉低的,
所以,即使主机把SDA置1了,之后再读取SDA,读到的值也可能是0,
读到0,代表从机给了应答,读到1,代表从机没给应答,这就是接收应答的流程。


*/

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  1. Κωδικός MPU6050:
#ifndef __MPU6050_REG_H
#define __MPU6050_REG_H

// 宏定义: 寄存器的名称   对应的地址

#define	MPU6050_SMPLRT_DIV		0x19  // 采样率分频
#define	MPU6050_CONFIG			0x1A  // 配置外部帧同步(FSYNC)引脚采样和数字低通滤波器(DLPF)设置
#define	MPU6050_GYRO_CONFIG		0x1B  // 触发陀螺仪自检和配置满量程
#define	MPU6050_ACCEL_CONFIG	0x1C  // 触发加速度计自检和配置满量程

#define	MPU6050_ACCEL_XOUT_H	0x3B  // 存储最新的加速度计测量值
#define	MPU6050_ACCEL_XOUT_L	0x3C
#define	MPU6050_ACCEL_YOUT_H	0x3D
#define	MPU6050_ACCEL_YOUT_L	0x3E
#define	MPU6050_ACCEL_ZOUT_H	0x3F
#define	MPU6050_ACCEL_ZOUT_L	0x40
#define	MPU6050_TEMP_OUT_H		0x41  // 存储最新的温度传感器测量值
#define	MPU6050_TEMP_OUT_L		0x42
#define	MPU6050_GYRO_XOUT_H		0x43  // 存储最新的陀螺仪测量值
#define	MPU6050_GYRO_XOUT_L		0x44
#define	MPU6050_GYRO_YOUT_H		0x45
#define	MPU6050_GYRO_YOUT_L		0x46
#define	MPU6050_GYRO_ZOUT_H		0x47
#define	MPU6050_GYRO_ZOUT_L		0x48

#define	MPU6050_PWR_MGMT_1		0x6B  // 电源管理寄存器1
#define	MPU6050_PWR_MGMT_2		0x6C  // 电源管理寄存器2
#define	MPU6050_WHO_AM_I		0x75  // 用于验证设备身份

#endif

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
#include "stm32f10x.h"                  // Device header
#include "MyI2C.h"
#include "MPU6050_Reg.h"

// 宏定义:从机地址
#define MPU6050_ADDRESS  0xD0

// 指定地址写
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_ADDRESS);// 发送从机地址后,接收应答
	MyI2C_ReceiveAck();// 寻址找到从机之后,继续发送下一个字节
	MyI2C_SendByte(RegAddress); // 指定寄存器地址,存在MPU6050的当前地址指针里,用于指定具体读写哪个寄存器
	MyI2C_ReceiveAck();
	MyI2C_SendByte(Data);// 指定写入指定寄存器地址下的数据
	MyI2C_ReceiveAck();
	MyI2C_Stop();
}

// 指定地址读
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
	uint8_t Data;
	
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_ADDRESS);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(RegAddress); // 指定地址:就是设置了MPU6050的当前地址指针
	MyI2C_ReceiveAck();
	// 转入读的时序,重新指定读写位,就必须重新起始
	MyI2C_Start();// 重复起始条件
	MyI2C_SendByte(MPU6050_ADDRESS | 0x01);// 指定从机地址和读写位,0xD0是写地址,或上0x01变为0xD1,读写位为1,接下来要读从机的数据
	MyI2C_ReceiveAck(); // 接收应答后,总线控制权就正式交给从机了,从机开始发送一个字节
	Data = MyI2C_ReceiveByte();// 主机接收一个字节,该函数返回值就是接收到的数据
	// 主机接收一个字节后,要给从机发送一个应答
	MyI2C_SendAck(1);// 参数为0,就是给从机应答,参数给1,就是不给从机应答
	// 如果想继续读多个字节,就要给应答,从机收到应答之后,就会继续发送数据,如果不想继续读了,就不能给从机应答了。
	// 主机收回总线的控制权,防止之后进入从机以为你还想要,但你实际不想要的冲突状态,
	// 这里,只需要读取1个字节,所以就给1,不给从机应答,
	MyI2C_Stop();
	return Data;
}

void MPU6050_Init(void)
{
	MyI2C_Init();
	// 写入一些寄存器对MPU6050硬件电路进行初始化配置
	// 电源管理寄存器1:设备复位:0,不复位;睡眠模式:0,解除睡眠:循环模式:0,不循环;无关位i:0;温度传感器失能:0,不失能;最后三位选择时钟:000,选择内部时钟,001,选择x轴的陀螺仪时钟,
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01);// 解除睡眠,选择陀螺仪时钟
	// 电源管理寄存器2:前两位,循环模式唤醒频率:00,不需要;后6位,每一个轴的待机位:全为0,不需要待机;
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00); // 均不待机
	// 采样率分频:该8位决定了数据输出的快慢,值越小越快
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);// 采样分频:10分频
	// 配置寄存器:外部同步:全为0,不需要;数字低通滤波器:110,最平滑的滤波
	MPU6050_WriteReg(MPU6050_CONFIG,0x06);// 滤波参数给最大
	// 陀螺仪配置寄存器:前三位,自测使能:全为0,不自测;满量程选择:11,最大量程;后三位无关位:为0
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18);// 陀螺仪和加速度计都选最大量程
	// 加速度计配置寄存器:前三位,自测使能:全为0,不自测;满量程选择:11,最大量程;后三位高通滤波器:用不到,为000
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18);
		
}

// 获取芯片的ID号
uint8_t MPU6050_GetID(void)
{
	return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}

// 获取寄存器数据的函数,返回6个int16_t的数据,分别表示XYZ的加速度值和陀螺仪值
// 指针地址传递的方法,返回多值
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ,
	                 int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
{
	uint8_t DataH, DataL;
	// 加速度计X
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	*AccX = (DataH << 8) | DataL; // 高8位左移8位,再或上低8位,得到加速度计X轴的16位数据
	// 加速度计Y
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
	*AccY = (DataH << 8) | DataL;
	// 加速度计Z
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
	*AccZ = (DataH << 8) | DataL;
	// 陀螺仪X
	DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
	*GyroX = (DataH << 8) | DataL;
	// 陀螺仪Y
	DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);
	*GyroY = (DataH << 8) | DataL;
	// 陀螺仪Z
	DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);
	*GyroZ = (DataH << 8) | DataL;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyI2C.h"
#include "MPU6050.h"

uint8_t ID;
int16_t AX, AY, AZ, GX, GY, GZ;// 接收XYZ轴的加速度值和陀螺仪值



int main(void)
{
	OLED_Init();
//	MyI2C_Init();
	MPU6050_Init();
//	
	OLED_ShowString(1,1,"ID:");
	ID = MPU6050_GetID();
	OLED_ShowHexNum(1, 4, ID, 2);
	
//	// 指定地址写
//	MyI2C_Start(); // 产生起始条件,开始一次传输
//	// 主机首先发送一个字节,内容是从机地址+读写位,进行寻址
//	MyI2C_SendByte(0xD0);  // 1101 000 0,0代表即将进行写入操作
//	// 发送一个字节后,要接收一下应答位,看看从机有没有收到刚才的数据
//	uint8_t Ack = MyI2C_ReceiveAck();
//	// 接收应答之后,要继续发送一个字节,写入寄存器地址
//	MyI2C_Stop();
//	
//	OLED_ShowNum(1, 1, Ack, 3);
	
//	// 指定地址读
//	uint8_t ID = MPU6050_ReadReg(0X75);// 返回值是0x68
//	OLED_ShowHexNum(1, 1, ID, 2);
	
//	// 指定地址写,需要先解除睡眠模式,否则写入无效
//	// 睡眠模式是电源管理寄存器1的这一位SLEEP控制的,把该寄存器写入0x00,解除睡眠模式
//	// 该寄存器地址是0x6B
//	MPU6050_WriteReg(0x6B, 0x00);
//	// 采样率分频寄存器,地址是0x19,值的内容是采样分频
//	MPU6050_WriteReg(0x19, 0xAA);
//	
//	uint8_t ID = MPU6050_ReadReg(0X19);
//	OLED_ShowHexNum(1, 1, ID, 2);//显示0x19地址下的内容,应该是0xAA
	
	while(1)
	{
		MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);
		OLED_ShowSignedNum(2, 1, AX, 5);
		OLED_ShowSignedNum(3, 1, AY, 5);
		OLED_ShowSignedNum(4, 1, AZ, 5);
		OLED_ShowSignedNum(2, 8, GX, 5);
		OLED_ShowSignedNum(3, 8, GY, 5);
		OLED_ShowSignedNum(4, 8, GZ, 5);
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

4. Περιφερειακά I2C

4.1 Εισαγωγή στα περιφερειακά I2C

  • Το STM32 ενσωματώνει ένα κύκλωμα πομποδέκτη I2C υλικού, το οποίο μπορεί να εκτελέσει αυτόματα λειτουργίες όπως δημιουργία ρολογιού, δημιουργία κατάστασης έναρξης και λήξης, μετάδοση και λήψη bit απόκρισης και μετάδοση και λήψη δεδομένων από το υλικό, μειώνοντας την επιβάρυνση της CPU.
  • Υποστήριξη μοντέλου πολλαπλών κεντρικών υπολογιστών
  • Υποστήριξη λειτουργίας διεύθυνσης 7-bit/10-bit
  • Υποστηρίζει διαφορετικές ταχύτητες επικοινωνίας, τυπική ταχύτητα (έως 100 kHz), γρήγορη (έως 400 kHz)
  • Υποστήριξη DMA
  • Συμβατό με το πρωτόκολλο SMBus
  • Πόροι I2C υλικού STM32F103C8T6: I2C1, I2C2

4.2 Μπλοκ διάγραμμα I2C

image.png

  • Στα αριστερά υπάρχουν οι ακίδες επικοινωνίας: Το SDA και το SCL χρησιμοποιούνται από το SMBus.
    Οι ακίδες που προέρχονται από γενικά περιφερειακά συνήθως συνδέονται με τον έξω κόσμο μέσω της λειτουργίας πολυπλεξίας της θύρας GPIO (δείτε τον πίνακα)
  • Το παραπάνω είναι το τμήμα ελέγχου δεδομένων: SDA Το βασικό μέρος της μετάδοσης και λήψης δεδομένων είναι ο καταχωρητής δεδομένων DR (DATA REGISTER) και ο καταχωρητής μετατόπισης δεδομένων. Όταν πρέπει να σταλούν δεδομένα, ένα byte δεδομένων μπορεί να εγγραφεί στον καταχωρητή δεδομένων DR Όταν ο καταχωρητής shift δεν έχει δεδομένα για μετατόπιση, η τιμή του καταχωρητή δεδομένων θα μεταφερθεί περαιτέρω στον καταχωρητή μετατόπισης. Κατά τη διαδικασία μετατόπισης, τα επόμενα δεδομένα μπορούν να τοποθετηθούν απευθείας στον καταχωρητή δεδομένων και να περιμένουν. Μόλις ολοκληρωθεί η προηγούμενη μετατόπιση δεδομένων, τα επόμενα δεδομένα μπορούν να συνδεθούν απρόσκοπτα και να συνεχίσουν να αποστέλλονται. Όταν τα δεδομένα μεταφέρονται από τον καταχωρητή δεδομένων στον καταχωρητή μετατόπισης, το bit TXE του καταχωρητή κατάστασης ορίζεται σε 1, υποδεικνύοντας ότι ο καταχωρητής μετάδοσης είναι κενός.
  • Λήψη: Τα δεδομένα εισόδου μετακινούνται από τον ακροδέκτη στον καταχωρητή shift bit-bit Όταν συλλέγεται ένα byte δεδομένων, τα δεδομένα μεταφέρονται από τον καταχωρητή shift στον καταχωρητή δεδομένων ως σύνολο και η σημαία RXNE ορίζεται στο την ίδια στιγμή, υποδεικνύοντας τη λήψη Ο καταχωρητής δεν είναι κενός, τότε τα δεδομένα μπορούν να διαβαστούν από το μητρώο δεδομένων. Όσον αφορά το πότε να λάβετε και πότε να στείλετε, πρέπει να γράψετε τα αντίστοιχα bit στον καταχωρητή ελέγχου για λειτουργία.
  • Ο συγκριτής και ο καταχωρητής διευθύνσεων χρησιμοποιούνται σε λειτουργία υποτελούς λειτουργίας.
  • SCL: Ο έλεγχος ρολογιού χρησιμοποιείται για τον έλεγχο της γραμμής SCL. Γράψτε το αντίστοιχο bit στον καταχωρητή ελέγχου ρολογιού και το κύκλωμα θα εκτελέσει την αντίστοιχη λειτουργία. Λογικό κύκλωμα ελέγχου, η εγγραφή στον καταχωρητή ελέγχου μπορεί να ελέγξει ολόκληρο το κύκλωμα. Η κατάσταση λειτουργίας του κυκλώματος μπορεί να γίνει γνωστή διαβάζοντας τον καταχωρητή κατάστασης.
  • Κατά την αποστολή και λήψη πολλών byte, το DMA μπορεί να χρησιμοποιηθεί για τη βελτίωση της αποτελεσματικότητας.

4.3 Βασική δομή I2C

image.png

  • SDA: Εφόσον το I2C είναι πρώτα υψηλής τάξης, αυτός ο καταχωρητής μετατόπισης μετατοπίζεται προς τα αριστερά. Κατά την αποστολή, το υψηλό bit μετακινείται πρώτα και μετά το δεύτερο υψηλό bit. Ένα ρολόι SCL μετατοπίζεται μία φορά και μετατοπίζεται 8 φορές και 8 byte μπορούν να τοποθετηθούν στη γραμμή SDA από υψηλό bit σε χαμηλό bit. Κατά τη λήψη, τα δεδομένα μετακινούνται από τα δεξιά μέσω της θύρας GPIO και, τέλος, 8 φορές, λαμβάνεται ένα byte. Τα δεδομένα εξόδου εξάγονται στη θύρα μέσω της θύρας GPIO. Τα δεδομένα εισόδου εισάγονται στον καταχωρητή shift μέσω της θύρας GPIO.
  • Η θύρα GPIO πρέπει να διαμορφωθεί σε λειτουργία εξόδου πολλαπλής αποστράγγισης σημαίνει ότι η κατάσταση της θύρας GPIO ελέγχεται από περιφερειακά στο τσιπ και η έξοδος ανοιχτής αποστράγγισης είναι η διαμόρφωση θύρας που απαιτείται από το πρωτόκολλο I2C. Ακόμη και σε λειτουργία εξόδου ανοιχτής αποστράγγισης, η θύρα GPIO μπορεί να εισαχθεί.
  • SCL: Ο ελεγκτής ρολογιού ελέγχει τη γραμμή του ρολογιού μέσω του GPIO.
    image.png

4.4 Αποστολές κεντρικού υπολογιστή

image.png
Όταν το STM32 θέλει να γράψει σε μια καθορισμένη διεύθυνση, πρέπει να ακολουθήσει το διάγραμμα ακολουθίας μετάδοσης πομπού.

  • Διεύθυνση 7-bit: Διευθυνσιοδοτείται το ένα byte μετά την συνθήκη έναρξης
  • Διεύθυνση 10-bit: Τα δύο byte μετά τη συνθήκη έναρξης είναι διευθυνσιοδοτήσεις Καθαρή διεύθυνση 8-bit.
  • Διαδικασία 7 bit: έναρξη, υποτελής διεύθυνση, απόκριση, δεδομένα, απόκριση, δεδομένα, απόκριση... Διακοπή
  1. Μετά την αρχικοποίηση, ο δίαυλος ορίζεται από προεπιλογή σε κατάσταση αδράνειας και STM από προεπιλογή σε κατάσταση υποτελούς λειτουργίας Για να δημιουργηθεί μια συνθήκη έναρξης, το STM32 πρέπει να γράψει στον καταχωρητή ελέγχου (CR1), να γράψει 1 και, στη συνέχεια, το STM32 αλλάζει από κατάσταση υποτελούς λειτουργίας σε λειτουργία κύριας. .

image.png

  1. Το συμβάν EV5 μπορεί να θεωρηθεί ως ένα bit σημαίας SB είναι ένα bit του καταχωρητή κατάστασης, υποδεικνύοντας την κατάσταση του υλικού SB=1.

image.png

  1. Στη συνέχεια, μπορείτε να στείλετε ένα byte της εξαρτημένης διεύθυνσης. Η δευτερεύουσα διεύθυνση πρέπει να γραφτεί στον καταχωρητή δεδομένων DR. αποστέλλεται στο δίαυλο I2C και, στη συνέχεια, το υλικό θα λάβει αυτόματα την απάντηση και θα κρίνει εάν δεν υπάρχει απάντηση, το υλικό θα ορίσει τη σημαία αποτυχίας απόκρισης και, στη συνέχεια, η σημαία μπορεί να υποβάλει αίτηση για διακοπή για να μας υπενθυμίσει.
  2. Όταν ολοκληρωθεί η διευθυνσιοδότηση, θα συμβεί το συμβάν EV6 και το bit σημαίας ADDR θα είναι 1. Αυτό το bit σημαίας υποδεικνύει το τέλος της μετάδοσης διεύθυνσης σε λειτουργία κύριας λειτουργίας.

image.png

  1. Το συμβάν EV8_1 σημαίνει ότι η σημαία TxE είναι 1, ο καταχωρητής shift είναι κενός και ο καταχωρητής δεδομένων είναι άδειος θα αλλάξει αμέσως στο shift. Το συμβάν EV8 θα συμβεί Ο καταχωρητής shift δεν είναι κενός και ο καταχωρητής δεδομένων είναι κενός, πράγμα που σημαίνει ότι ο καταχωρητής μετατόπισης αποστέλλει δεδομένα. Αυτή τη στιγμή, τα δεδομένα 2 θα εγγραφούν στον καταχωρητή δεδομένων και βρίσκονται σε αναμονή Μετά τη λήψη του bit απόκρισης, τα bit δεδομένων μεταφέρονται στον καταχωρητή στροφής για μετάδοση Ο καταχωρητής δεδομένων είναι κενός, οπότε αυτή τη στιγμή, το περιστατικό EV8 συνέβη ξανά.
  2. Στη συνέχεια αποστέλλονται τα δεδομένα 2, αλλά αυτή τη φορά τα επόμενα δεδομένα έχουν γραφτεί στον καταχωρητή δεδομένων και περιμένουν. Μόλις εντοπιστεί το συμβάν EV8, μπορούν να εγγραφούν τα επόμενα δεδομένα.
  3. Αφού εγγραφούν τα δεδομένα που θέλετε να στείλετε, δεν εγγράφονται νέα δεδομένα στον καταχωρητή δεδομένων. Συμβάν EV8_2, TxE=1 σημαίνει ότι ο καταχωρητής μετατόπισης είναι κενός, ο καταχωρητής δεδομένων είναι κενός, BTF: σημαία λήξης μετάδοσης byte, κατά τη μετάδοση, πότε θα σταλεί νέα δεδομένα και ο καταχωρητής δεδομένων δεν έχει γραφτεί με νέα δεδομένα. Όταν εντοπιστεί EV8_2, μπορεί να δημιουργηθεί η συνθήκη τερματισμού Stop. Για να δημιουργηθεί μια συνθήκη τερματισμού, προφανώς, θα πρέπει να υπάρχουν αντίστοιχα bits στον καταχωρητή ελέγχου που μπορούν να ελεγχθούν. Με αυτόν τον τρόπο, η ακολουθία αποστολής έχει τελειώσει.

4.5 Υποδοχή υποδοχής

image.png
Κύρια λήψη 7 bit: έναρξη, υποτελής διεύθυνση + ανάγνωση, λήψη απάντησης, λήψη δεδομένων, αποστολή απάντησης... λήψη δεδομένων, μη απόκριση, τερματισμός

  1. Πρώτα, γράψτε το bit έναρξης του καταχωρητή ελέγχου για να δημιουργήσετε μια συνθήκη έναρξης και, στη συνέχεια, περιμένετε για το συμβάν EV5 (που υποδεικνύει ότι η συνθήκη έναρξης έχει σταλεί).
  2. Μετά τη διευθυνσιοδότηση, λαμβάνεται η απάντηση και μετά το τέλος δημιουργείται ένα συμβάν EV6 (που υποδεικνύει ότι η διευθυνσιοδότηση έχει ολοκληρωθεί).
  3. Δεδομένα 1 σημαίνει ότι τα δεδομένα εισάγονται μέσω του καταχωρητή μετατόπισης.
  4. Το EV6_1 υποδεικνύει ότι τα δεδομένα εξακολουθούν να μετατοπίζονται Μετά τη λήψη της απάντησης, σημαίνει ότι ο καταχωρητής μετατόπισης έχει μετακινηθεί επιτυχώς σε ένα byte δεδομένων 1. Αυτή τη στιγμή, το μετατοπισμένο byte μεταφέρεται στον καταχωρητή δεδομένων ως σύνολο. Η σημαία RxNE ορίζεται ταυτόχρονα, υποδεικνύοντας ότι ο καταχωρητής δεδομένων δεν είναι κενός, δηλαδή έχει ληφθεί ένα byte δεδομένων. Η κατάσταση είναι ένα συμβάν EV7, RxNE=1 διαγράφει το συμβάν ότι τα δεδομένα έχουν ληφθεί Αφού διαβάσουμε τα δεδομένα, το συμβάν Δεν υπάρχει άλλο.
  5. Φυσικά, όταν τα δεδομένα 1 δεν έχουν διαβαστεί, τα δεδομένα 2 μπορούν να μετακινηθούν απευθείας στον καταχωρητή μετατόπισης Μετά από αυτό, η μετατόπιση των δεδομένων 2 ολοκληρώνεται, τα δεδομένα 2 λαμβάνονται, ένα συμβάν EV7 δημιουργείται, τα δεδομένα 2 διαβάζονται και. το συμβάν EV7 έχει φύγει.
  6. Όταν δεν χρειάζεται άλλη λήψη, ο καταχωρητής ελέγχου bit απόκρισης ACK πρέπει να ρυθμιστεί εκ των προτέρων στο 0 όταν εμφανιστεί η τελευταία μονάδα χρονισμού και να οριστεί το αίτημα τερματισμού, δηλαδή το συμβάν EV7_1, στη συνέχεια, ένα συμβάν μη απόκρισης Θα δοθεί αφού έχει οριστεί το bit STOP, δημιουργείται μια συνθήκη τερματισμού.

4.6 Σύγκριση κυματομορφής λογισμικού/υλισμικού

image.png

image.png

5. 10-2 Hardware I2C ανάγνωση και εγγραφή MPU6050

5.1 Λειτουργίες βιβλιοθήκης I2C


void I2C_DeInit(I2C_TypeDef* I2Cx);
void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct);
void I2C_StructInit(I2C_InitTypeDef* I2C_InitStruct);
void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState);

// 生成起始条件、终止条件
void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState);
void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState);

// 配置CR1的ACK这一位,0:无应答,1:应答
void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState);

// 发送数据,把Data数据直接写入到DR寄存器
void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data);
// 读取DR,接收数据
uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);

// Address参数也是通过DR发送的,但在发送之前,设置了Address最低位的读写位,
// I2C_Direction不是发送,是把Address的最低位置1(读),否则最低位清0(写)
void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

5.2 Υλικό I2C για ανάγνωση και εγγραφή MPU6050

5.2.1 Σύνδεση υλικού

Το SCL συνδέεται με τον ακροδέκτη PB10 του STM32 και το SDA συνδέεται στον ακροδέκτη PB11. Δεδομένου ότι η αναστροφή επιπέδου λογισμικού εφαρμόζεται εδώ, δύο θύρες GPIO μπορούν να συνδεθούν κατά βούληση.
Τα κορυφαία δεδομένα του OLED είναι ο αριθμός ID της συσκευής Ο αριθμός ID αυτού του MPU6050 είναι σταθερός στο 0x68. Παρακάτω, τα τρία στα αριστερά είναι τα δεδομένα εξόδου του αισθητήρα επιτάχυνσης, τα οποία είναι η επιτάχυνση του άξονα X, του άξονα Y και του άξονα Z αντίστοιχα. που είναι η γωνιακή ταχύτητα του άξονα Χ, του άξονα Υ και του άξονα Ζ.

5.2.2 Αποτελέσματα λειτουργίας

IMG_20240406_172128.jpg

5.2.3 Διαδικασία εφαρμογής κώδικα

  1. Διαμόρφωση περιφερειακών I2C, προετοιμασία περιφερειακών I2C, αντικατάσταση MyI2C_Init
    (1) Ενεργοποιήστε το ρολόι της περιφερειακής συσκευής I2C και της αντίστοιχης θύρας GPIO,
    (2) Εκκινήστε τη θύρα GPIO που αντιστοιχεί στο περιφερειακό I2C στη λειτουργία πολυπλεξίας ανοιχτής αποστράγγισης
    (3) Χρησιμοποιήστε τη δομή για να διαμορφώσετε ολόκληρο το I2C
    (4) I2C_Cmd, ενεργοποιήστε το I2C
  2. Ελέγξτε τα περιφερειακά κυκλώματα, συνειδητοποιήστε το χρόνο εγγραφής σε καθορισμένες διευθύνσεις και αντικαταστήστε το WriteReg
  3. Ελέγξτε το περιφερειακό κύκλωμα για να συνειδητοποιήσετε το χρονισμό της ανάγνωσης της καθορισμένης διεύθυνσης και αντικαταστήστε το ReadReg

5.2.4 Κωδ

  1. Κωδικός MPU6050:
#include "stm32f10x.h"                  // Device header
#include "MPU6050_Reg.h"

/*
1. 配置I2C外设,对I2C外设进行初始化,替换MyI2C_Init
   (1)开启I2C外设和对应GPIO口的时钟,
   (2)把I2C外设对应的GPIO口初始化为复用开漏模式
   (3)使用结构体,对整个I2C进行配置
   (4)I2C_Cmd,使能I2C
2. 控制外设电路,实现指定地址写的时序,替换WriteReg
3. 控制外设电路,实现指定地址读的时序,替换ReadReg
*/


// 宏定义:从机地址
#define MPU6050_ADDRESS  0xD0
 
// 超时退出
void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
	uint32_t TimeOut;
	TimeOut = 10000;
	while (I2C_CheckEvent(I2Cx, I2C_EVENT) != SUCCESS) 
	{   
		TimeOut --;
		if (TimeOut == 0)
		{
			break;// 跳出循环,直接执行后面的程序
		}
	}
}

// 指定地址写:发送器传送时序
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
//	MyI2C_Start();
//	MyI2C_SendByte(MPU6050_ADDRESS);// 发送从机地址后,接收应答
//	MyI2C_ReceiveAck();// 寻址找到从机之后,继续发送下一个字节
//	MyI2C_SendByte(RegAddress); // 指定寄存器地址,存在MPU6050的当前地址指针里,用于指定具体读写哪个寄存器
//	MyI2C_ReceiveAck();
//	MyI2C_SendByte(Data);// 指定写入指定寄存器地址下的数据
//	MyI2C_ReceiveAck();
//	MyI2C_Stop();
	
	I2C_GenerateSTART(I2C2, ENABLE); // 起始条件
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT); //EV5事件
	
	// 发送从机地址,接收应答。该函数自带了接收应答,如果应答错误,硬件会通过标志位和中断来提示我们
	I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);
	
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //EV6事件
	
	// 直接写入DR,发送数据
	I2C_SendData(I2C2, RegAddress);
	// 写入了DR,DR立刻转移到移位寄存器进行发送,EV8事件出现的非常快,基本不用等。因为有两级缓存,
	// 第一个数据写进DR了,会立刻跑到移位寄存器,这时不用等第一个数据发完,第二个数据就可以写进去等着了。
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING); //EV8事件
	
	I2C_SendData(I2C2, Data);
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED); //EV8_2事件
	
	I2C_GenerateSTOP(I2C2, ENABLE);
}

// 指定地址读:接收器传送序列
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
	uint8_t Data;
	
//	MyI2C_Start();
//	MyI2C_SendByte(MPU6050_ADDRESS);
//	MyI2C_ReceiveAck();
//	MyI2C_SendByte(RegAddress); // 指定地址:就是设置了MPU6050的当前地址指针
//	MyI2C_ReceiveAck();
//	// 转入读的时序,重新指定读写位,就必须重新起始
//	MyI2C_Start();// 重复起始条件
//	MyI2C_SendByte(MPU6050_ADDRESS | 0x01);// 指定从机地址和读写位,0xD0是写地址,或上0x01变为0xD1,读写位为1,接下来要读从机的数据
//	MyI2C_ReceiveAck(); // 接收应答后,总线控制权就正式交给从机了,从机开始发送一个字节
//	Data = MyI2C_ReceiveByte();// 主机接收一个字节,该函数返回值就是接收到的数据
//	// 主机接收一个字节后,要给发送从机一个应答
//	MyI2C_SendAck(1);// 参数为0,就是给从机应答,参数给1,就是不给从机应答
//	MyI2C_Stop();
	
	
	I2C_GenerateSTART(I2C2, ENABLE); // 起始条件
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT); //EV5事件
	
	// 发送从机地址,接收应答。该函数自带了接收应答,如果应答错误,硬件会通过标志位和中断来提示我们
	I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);
	
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //EV6事件
	
	// 直接写入DR,发送数据
	I2C_SendData(I2C2, RegAddress);
	// 写入了DR,DR立刻转移到移位寄存器进行发送,EV8事件出现的非常快,基本不用等。因为有两级缓存,
	// 第一个数据写进DR了,会立刻跑到移位寄存器,这时不用等第一个数据发完,第二个数据就可以写进去等着了。
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED); //EV8_2事件
	
	I2C_GenerateSTART(I2C2, ENABLE);// 重复起始条件
	
	// 主机接收
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT); //EV5事件
	// 接收地址
	I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Receiver); // 函数内部就自动将该地址MPU6050_ADDRESS的最低位置1
	
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED); //EV6事件
	
	// 在最后一个数据之前就要把应答位ACK置0,同时把停止条件生成位STOP置1
	I2C_AcknowledgeConfig(I2C2, DISABLE);
	I2C_GenerateSTOP(I2C2, ENABLE);
	
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED); //EV7事件
	// 等EV7事件产生后,一个字节的数据就已经在DR里面了。
	// 读取DR就可拿出该字节
	Data = I2C_ReceiveData(I2C2); // 返回值就是DR的数据
	// 在接收函数的最后,要恢复默认的ACK = 1。
	// 默认状态下ACK就是1,给从机应答,在收最后一个字节之前,临时把ACK置0,给非应答,
	// 所以在接收函数的最后,要恢复默认的ACK = 1,这个流程是为了方便指定地址收多个字节。
	I2C_AcknowledgeConfig(I2C2, ENABLE);
	
	return Data;
}

void MPU6050_Init(void)
{
	
//	MyI2C_Init();
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 复用开漏
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	I2C_InitTypeDef I2C_InitStructure;
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; // 模式
	I2C_InitStructure.I2C_ClockSpeed = 50000; // 时钟速度,最大400kHz的时钟频率
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;	// 时钟占空比,只有在时钟频率大于100kHz,也就是进入到快速状态时才有用,小于100kHz,占空比是固定的1:1,
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; //
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // STM32作为从机,可以响应几位的地址
	I2C_InitStructure.I2C_OwnAddress1 = 0x00; // 自身地址1,也是作为从机使用,
	I2C_Init(I2C2, &I2C_InitStructure); 
	
	I2C_Cmd(I2C2,ENABLE);
	
	// 写入一些寄存器对MPU6050硬件电路进行初始化配置
	// 电源管理寄存器1:设备复位:0,不复位;睡眠模式:0,解除睡眠:循环模式:0,不循环;无关位i:0;温度传感器失能:0,不失能;最后三位选择时钟:000,选择内部时钟,001,选择x轴的陀螺仪时钟,
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01);// 解除睡眠,选择陀螺仪时钟
	// 电源管理寄存器2:前两位,循环模式唤醒频率:00,不需要;后6位,每一个轴的待机位:全为0,不需要待机;
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00); // 均不待机
	// 采样率分频:该8位决定了数据输出的快慢,值越小越快
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);// 采样分频:10分频
	// 配置寄存器:外部同步:全为0,不需要;数字低通滤波器:110,最平滑的滤波
	MPU6050_WriteReg(MPU6050_CONFIG,0x06);// 滤波参数给最大
	// 陀螺仪配置寄存器:前三位,自测使能:全为0,不自测;满量程选择:11,最大量程;后三位无关位:为0
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18);// 陀螺仪和加速度计都选最大量程
	// 加速度计配置寄存器:前三位,自测使能:全为0,不自测;满量程选择:11,最大量程;后三位高通滤波器:用不到,为000
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18);
		
}

// 获取芯片的ID号
uint8_t MPU6050_GetID(void)
{
	return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}

// 获取寄存器数据的函数,返回6个int16_t的数据,分别表示XYZ的加速度值和陀螺仪值
// 指针地址传递的方法,返回多值
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ,
	                 int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
{
	uint8_t DataH, DataL;
	// 加速度计X
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	*AccX = (DataH << 8) | DataL; // 高8位左移8位,再或上低8位,得到加速度计X轴的16位数据
	// 加速度计Y
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
	*AccY = (DataH << 8) | DataL;
	// 加速度计Z
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
	*AccZ = (DataH << 8) | DataL;
	// 陀螺仪X
	DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
	*GyroX = (DataH << 8) | DataL;
	// 陀螺仪Y
	DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);
	*GyroY = (DataH << 8) | DataL;
	// 陀螺仪Z
	DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);
	*GyroZ = (DataH << 8) | DataL;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  1. κύρια.γ
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"

uint8_t ID;
int16_t AX, AY, AZ, GX, GY, GZ;// 接收XYZ轴的加速度值和陀螺仪值



int main(void)
{
	OLED_Init();
	MPU6050_Init();
	
	OLED_ShowString(1,1,"ID:");
	ID = MPU6050_GetID();
	OLED_ShowHexNum(1, 4, ID, 2);
	
//	// 指定地址写
//	MyI2C_Start(); // 产生起始条件,开始一次传输
//	// 主机首先发送一个字节,内容时从机地址+读写位,进行寻址
//	MyI2C_SendByte(0xD0);  // 1101 000 0,0代表即将进行写入操作
//	// 发送一个字节后,要接收一下应答位,看看从机有没有收到刚才的数据
//	uint8_t Ack = MyI2C_ReceiveAck();
//	// 接收应答之后,要继续发送一个字节,写入寄存器地址
//	MyI2C_Stop();
//	
//	OLED_ShowNum(1, 1, Ack, 3);
	
//	// 指定地址读
//	uint8_t ID = MPU6050_ReadReg(0X75);// 返回值是0x68
//	OLED_ShowHexNum(1, 1, ID, 2);
	
//	// 指定地址写,需要先解除睡眠模式,否则写入无效
//	// 睡眠模式是电源管理寄存器1的这一位SLEEP控制的,把该寄存器写入0x00,解除睡眠模式
//	// 该寄存器地址是0x6B
//	MPU6050_WriteReg(0x6B, 0x00);
//	// 采样率分频寄存器,地址是0x19,值的内容是采样分频
//	MPU6050_WriteReg(0x19, 0xAA);
//	
//	uint8_t ID = MPU6050_ReadReg(0X19);
//	OLED_ShowHexNum(1, 1, ID, 2);//显示0x19地址下的内容,应该是0xAA
	
	
	
	while(1)
	{
		MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);
		OLED_ShowSignedNum(2, 1, AX, 5);
		OLED_ShowSignedNum(3, 1, AY, 5);
		OLED_ShowSignedNum(4, 1, AZ, 5);
		OLED_ShowSignedNum(2, 8, GX, 5);
		OLED_ShowSignedNum(3, 8, GY, 5);
		OLED_ShowSignedNum(4, 8, GZ, 5);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57