Compare commits

...

37 commits

Author SHA1 Message Date
a2d245df7e Accelerometre.c est maintenant plus mince, et aucun des programmes utilisent Timer.c, mais plutot Horloge.c 2025-12-02 11:27:22 +01:00
fbc87e8a21 Accelerometre.c est maintenant plus mince, et aucun des programmes utilisent Timer.c, mais plutot Horloge.c 2025-12-02 11:26:51 +01:00
a606e6331b J'ai oublié un } 2025-12-02 11:13:03 +01:00
1865c6f7c9 Màj pour correspondre au nouveau Accelerometre.c et .h 2025-12-02 11:01:29 +01:00
8d39fbf37d Màj pour que le .h corresponde au nouveau .c 2025-12-02 10:59:18 +01:00
80749ca592 Mise à jour de Acceleromètre.c pour correspondre au nouveau principal.c 2025-12-02 10:56:00 +01:00
6945cda99e Màj visuels dans le cote 2025-12-02 10:40:11 +01:00
24de81a301 Merge branch 'Accelerometre' of https://git.etud.insa-toulouse.fr/johnse/BE_VOILIER into Accelerometre
OUai
2025-12-02 10:38:03 +01:00
de73575fa7 Un principal.c moderne et mince, version finale à tester dans Keil. 2025-12-02 10:37:45 +01:00
c91ffdbedf Màj du README.md pour corriger l'affichage d'une photo 2025-12-02 10:06:49 +01:00
939647404e Suppression des ficher en double 2025-12-02 10:05:55 +01:00
d8baef8443 Suppression d'un document 2025-12-02 10:04:36 +01:00
f4ed19452d Ajout de beacoup de code pour gérér l'acceleromètre par SPI. Code à revoir 2025-12-02 09:52:51 +01:00
63fc720afa M.à.j. des commentaires 2025-11-24 18:09:11 +01:00
c9adc36066 Filer som trengs for compilation 2025-11-23 18:21:25 +01:00
6add9ea143 Adding main.c 2025-11-23 18:20:36 +01:00
f7f7c1b987 Doing minor changes 2025-11-23 18:14:49 +01:00
a4ee0a2cf8 Update README.md 2025-11-23 18:13:53 +01:00
d75491ac45 Upload files to "/" 2025-11-23 18:11:52 +01:00
8c08fd4ffc Upload files to "IMAGES" 2025-11-22 15:06:20 +01:00
5a4457b61e Librarie de l'acceleromètre par SPI 4 broches 2025-11-19 11:25:37 +01:00
31c72fd5f6 Upload files to "/"
Les travaux fait en séance 19/11. On est arrivé à récuperer le DATA de l'acceleromètre du voilier. Faut le tester en réel.
2025-11-19 11:24:36 +01:00
5f4ed0902c Update Informations_Generales/README.md 2025-11-19 09:31:48 +01:00
4e3e11aab2 Update Informations_Generales/README.md 2025-11-19 09:31:40 +01:00
d7b6391cd6 Update README.md 2025-11-19 09:31:16 +01:00
6dc2bc093c Update Informations_Generales/README.md 2025-11-19 09:30:49 +01:00
82f61ffcde Update Informations_Generales/README.md 2025-11-19 09:30:30 +01:00
5d6e9ccd85 Update Informations_Generales/README.md 2025-11-19 09:29:45 +01:00
03898d3d1c Delete IMAGES/HER 2025-11-19 09:29:26 +01:00
a2cb5212c7 Upload files to "IMAGES" 2025-11-19 09:29:18 +01:00
7e8a278228 Update IMAGES/HER 2025-11-19 09:29:02 +01:00
c371352520 Add Images 2025-11-19 09:27:54 +01:00
ee23278a02 Update README.md 2025-11-19 09:24:57 +01:00
0bad25a87c Update Informations_Generales/README.md 2025-11-19 09:21:51 +01:00
9a74614b25 Update Informations_Generales/README.md 2025-11-19 09:21:30 +01:00
b93583d501 Update Informations_Generales/Info_Datasheet 2025-11-19 09:20:43 +01:00
b67a2ae4ea Add Informations_Generales/Info_Datasheet
Ajout d'un fichier et un image du datasheet
2025-11-19 09:18:56 +01:00
23 changed files with 882 additions and 2 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
IMAGES/RegisterMap_SPI.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

BIN
IMAGES/Standby_PWCTL.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View file

@ -0,0 +1,3 @@
Notre RegisterMap
![RegisterMap](IMAGES/RegisterMap_SPI.png)

BIN
Lib_Com_Periph_2022.lib Normal file

Binary file not shown.

View file

@ -8,6 +8,10 @@ Bem vindo ao projeto veleiro de µcontroladores 4AE-SE 2025.
Welkom bij het microcontroller zeilbootproject 4AE-SE 2025.
##Le Navire actuellement
Actuellement la navire lâche les voiles dès qu'on a un "vent" trop fort.
##Les groupes et résponsabilités sont :
>>Nicolas et Jarno : Envoi de UART et PWM dans la bonne fréquence (canal), pour relier le voilier à l'ecran.
@ -22,5 +26,5 @@ Welkom bij het microcontroller zeilbootproject 4AE-SE 2025.
License : CC-BY-NC-SA 4.0
>>Register Map pour la SPI
![Cible](IMAGES/RegisterMap_SPI.png)

9
include/Accelerometre.h Normal file
View file

@ -0,0 +1,9 @@
#include <stm32f10x.h>
#include <stdint.h>
#define LONGUEUR_MOY 10
void initAccelo(void);
void initLacheur(void);
uint16_t * RecupAccelo(void);
void LacheVoile(int AngelLim, uint16_t moyennen);

17
include/DriverGPIO.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef DRIVERGPIO_H_
#define DRIVERGPIO_H_
#include "stm32f10x.h"
#define In_Floating 0x4
#define In_PullDown 0x8
#define In_PullUp 0x8
#define In_Analog 0x0
#define Out_Ppull 0x3
#define Out_OD 0x7
#define AltOut_Ppull 0xB
#define AltOut_OD 0xF
extern void MyGPIO_Init(GPIO_TypeDef * GPIO, char pin, char conf );
extern int MyGPIO_Read(GPIO_TypeDef * GPIO, char GPIO_Pin); // renvoie 0 ou autre chose different de 0
extern void MyGPIO_Set(GPIO_TypeDef * GPIO, char GPIO_Pin);
extern void MyGPIO_Reset(GPIO_TypeDef * GPIO, char GPIO_Pin);
extern void MyGPIO_Toggle(GPIO_TypeDef * GPIO, char GPIO_Pin);
#endif

16
include/Horloge.h Normal file
View file

@ -0,0 +1,16 @@
#include <stm32f10x.h>
#define PSC_VAL 624
#define ARR_VAL 0xE0FF
//DUTY CYCLE
#define DUTYC 70 //Chiffre entre 0 et 100, où 100 est 100% duty cycle
#define POWERMODE 1 // 1 vaut powermode 1, 0 vaut powermode 2 (Powermode pour le config de dutycycle)
//Powermode 1 reste sur la bonne polarité: cad. si DUTY_CYCLE vaut 60 alors le signal reste HIGH pour 60% du periode, inverse pour pwmd2
//Timer
void Timer_Init(TIM_TypeDef *Timer, unsigned short Autoreload, unsigned short Prescaler);
void MyTimer_ActiveIT(TIM_TypeDef * Timer, char Prio, void(*Interrupt_fonc)(void));
void TIM2_IRQHandler(void);
//PWM
void MyTimer_PWM(TIM_TypeDef * Timer , int Channel);
int Set_DutyCycle_PWM(TIM_TypeDef *Timer, int Channel, int DutyC);

38
include/MYGPIO.h Normal file
View file

@ -0,0 +1,38 @@
//Definitions
//INTERNE
#define LED_PIN_INTERNE (5) // 5 pour le LED de Arduino
#define BUTTON_GPIO_INTERNE (GPIOA) //GPIOA pour l'Arduion
#define LED_GPIO_INTERNE (GPIOA) //GPIOA pour Arduino
#define BUTTON_PIN_INTERNE (13) //13 pour Arduino
//EXTERNE
#define LED_PIN_EXTERNE (8) // 8 pour la porte PB8
#define BUTTON_GPIO_EXTERNE (GPIOB) //GPIOB pour externe
#define LED_GPIO_EXTERNE (GPIOB) //GPIOB pour Externe
#define BUTTON_PIN_EXTERNE (9) //9 pour bouton poussoir
//STATIQUES
#define GPIO_OUTPUT_PPULL_MODE (2) //Mis en GP output 2MHz en mode PP
#define GPIO_INPUT_PUPD_MODE (8) //Pour mettre à Pull up/down
#define GPIO_INPUT_FLOATING_MODE (4)
//si on est sur l'arduino ou sur le led externe
#define INTERNE 1 // 1 c'est vrai, 0 faux
//FONCTIONS
void initGPIO_Interne(void);
int boutonAppuye_Interne(void);
void allumerDEL_Interne(void);
void eteindreDEL_Interne(void);
void commuterDEL_Interne(void);
void allume_bit_Interne(void);
void initGPIO_Externe(void);
int boutonAppuye_Externe(void);
void allumerDEL_Externe(void);
void eteindreDEL_Externe(void);
void commuterDEL_Externe(void);
void allume_bit_Externe(void);

229
include/MyI2C.h Normal file
View file

@ -0,0 +1,229 @@
#ifndef _I2C_
#define _I2C_
#include "stm32f10x.h"
/*************************************************************************************
===================== By Periph team INSA GEI 2022 ===========================
*************************************************************************************/
/*
*************************************************************************************
===================== I2C les IO STM32F103 =================================
*************************************************************************************
Les IO sont pris en charge par la lib, pas besoin de faire les configurations Alt OD.
**I2C1**
SCL PB6
SDA PB7
**I2C2**
SCL PB10
SDA PB11
*************************************************************************************
==================== Fondamentaux I2C ==========================================
*************************************************************************************
- Bus synchrone Low speed (<100kHz) ou high speed (=400kHz), Ici Low speed 100kHz.
- Transfert octet par octet, poids fort en premier, avec aquittement pour chaque octet
- Deux lignes SDA et SCL (horloge) en open drain, repos '1'
- bit "normal" = SDA stable lors du pulse SCL (ie durant l'état haut de SCL, SDA est stable)
- bit Start/Stop/Restart = SDA non stable lorsque SCL vaut '1' (violation règle précédente)
* Start : front descendant de SDA lorsque SCL vaut '1'
* Stop : front montant de SDA lorsque SCL = '1'
* Restart = Start en cours de trame (typiquement pour changer Write/read).
- uC en Mode Master uniquement (c'est notre choix) : c'est le uC qui est maître de l'horloge SCL.
- Le Slave a une @ 7 bits. On ajoute un bit LSB qui est /WR (donc 0 pour écriture, 1 pour lecture)
- Une adresse s'écrit donc |a6 a5 a4 a3 a2 a1 a0 /WR| ce qui donne 8 bits. Elle indique une future
lecture ou écriture.
On parle d'@ 7 bits en regroupant |a6 a5 a4 a3 a2 a1 a0|
On parle d'@ 8 bits en regroupant |a6 a5 a4 a3 a2 a1 a0 /WR| (donc une @ écriture, une @ lecture)
NB : préférer le concept @7bits...c'est plus clair.
- On peut lire ou écrire une ou plusieurs données à la suite. C'est lors de l'envoie de l'adresse Slave
par le Master que le sens à venir pour les datas est indiqué.
- En écriture,
* les Ack sont faits par le slave après chaque octet envoyé par le master (Ack = mise à 0 le bit 9).
- En lecture,
* dès que le l@ slave est transmise (/RW = 1), et le Ack réalisé, le slave positionne le bit 7
du prochain octet à lire sur SDA par anticipation ,
* le master enchaîne ses pulses (9), lors du pulse 9 (le dernier) c'est le master qui acquite.
* Après chaque acquitement, le Slave amorce le prochain octet en positionnant son bit 7 sur SDA
* Après le dernier octet, le Master génère un stop.
* Pour pouvoir générer le stop, le Master doit piloter SDA, or ce n'est pas possible puisque
le Slave positionne le futur bit 7 ... Pour régler ce problème :
lors du dernier transfert, le Master N'acquitte PAS (NACK). Ainsi le Slave ne
propose plus le bit 7 du prochain octet sur SDA et libère SDA. Le Master peut alors clôturer la
communication avec un Stop.
======= Echange typique avec un Slave ================================================================
- Une lecture ou écriture se fait vers un Slave et à partir d'une adresse mémoire donnée (pointeur interne).
Ce pointeur est automatiquement incrémenté dans le slave lors des accès écriture ou lecture.
- Ecriture de N octets , trame complète (@ = adresse slave, pt = valeur de chargement du pointeur interne)
|Start Cond |@6|@5|@4|@3|@2|@1|@0| Wr =0 |Slave ACK|
|pt7|pt6|pt5|pt4|pt3|pt2|pt1|pt0|Slave ACK|
|d7|d6|d5|d4|d3|d2|d1|d0|Slave ACK| (data 1)
.....
|d7|d6|d5|d4|d3|d2|d1|d0|Salve ACK|Stop Cond| (data N)
- Lecture de N octets à partir d'une adresse de pointeur donnée
|Start Cond |@6|@5|@4|@3|@2|@1|@0| Wr =0 |Slave ACK|
|pt7|pt6|pt5|pt4|pt3|pt2|pt1|pt0|Slave ACK|
|ReStart Cond |@6|@5|@4|@3|@2|@1|@0| Wr =1 |Slave ACK| (NB: restart nécessaire pour changer écriture / lecture)
|d7|d6|d5|d4|d3|d2|d1|d0|Master ACK| (data 1)
.....
|d7|d6|d5|d4|d3|d2|d1|d0|Master ACK| (data N-1)
|d7|d6|d5|d4|d3|d2|d1|d0|Master NACK|Stop Cond| (data N)
*************************************************************************************
==================== La lib I2C ==========================================
*************************************************************************************
3 fonctions essentielles :
MyI2C_Init
MyI2C_PutString
MyI2C_GetString
1 fonction spéciale : MyI2C_Get_Error
Les fonctions Put/Get string fonctionnent sur le principe classique décrit précédemment
(Slave@, Pter @, Data...).
La fonction init prend parmi ses paramètres le nom d'une fct callback d'erreur.
En fait, le driver gère en IT les erreurs possibles I2C. La fonction MyI2C_Get_Error permet de
recevoir un code erreur.
Il est conseillé d'utiliser ce callback. Si on tombe dedans, c'est qu'une erreur s'est produite.
Si le code erreur est "inconnu", souvent c'est qu'il y a un soucis à l'adressage slave:
Vérifier alors la connectique physique SDA/SCL ainsi que l'alimentation du slave ou tout simplement
l'@ slave !
==========================================================================================*/
/*=========================================================================================
GESTION ERREURS
========================================================================================= */
typedef enum
{
OK,
BusError, //
AckFail, // Pas,d'ack
TimeOut, // SCL est resté plus de 25ms à l'état bas
UnknownError // IT erreur déclenchée mais pas de flag explicite ...
} MyI2C_Err_Enum;
/**
* @brief Retourne les erreurs I2C
* @param I2Cx: where x can be 1 or 2 to select the I2C peripheral.
* @retval Type d'erreur rencontrée , voir MyI2C_Err_Enum
*/
MyI2C_Err_Enum MyI2C_Get_Error(I2C_TypeDef * I2Cx);
/*=========================================================================================
INITIALISATION I2C
========================================================================================= */
/**
* @brief Initialise l'interface I2C (1 ou 2)
* @param I2Cx: where x can be 1 or 2 to select the I2C peripheral.
* @param char IT_Prio_I2CErr 0 à 15 (utilisé en cas d'erreur, IT courte et non bloquante
* @param *ITErr_function : callback à utiliser pour sortir d'un plantage transmission
* @retval None
* @Example MyI2C_Init(I2C1, 2,My_CallbackErr);
*/
void MyI2C_Init(I2C_TypeDef * I2Cx, char IT_Prio_I2CErr, void (*ITErr_function) (void));
/*=========================================================================================
EMISSION I2C : PutString
========================================================================================= */
// Structure de données pour l'émission ou la réception I2C :
typedef struct
{
char SlaveAdress7bits; // l'adresse I2C du slave device
char * Ptr_Data; // l'adresse du début de tableau char à recevoir/émettre (tableau en RAM uC)
char Nb_Data; // le nbre d'octets à envoyer / recevoir
}
MyI2C_RecSendData_Typedef;
/**
* @brief|Start Cond |@6|@5|@4|@3|@2|@1|@0| Wr =0 |Slave ACK|
|pt7|pt6|pt5|pt4|pt3|pt2|pt1|pt0|Slave ACK|
|d7|d6|d5|d4|d3|d2|d1|d0|Slave ACK| (data 1)
.....
|d7|d6|d5|d4|d3|d2|d1|d0|Salve ACK|Stop Cond| (data N)
* @param I2Cx: where x can be 1 or 2 to select the I2C peripheral.
* @param PteurAdress = adresse de démarrage écriture à l'interieur du slave I2C
* @param DataToSend, adresse de la structure qui contient les informations à transmettre
voir définition MyI2C_RecSendData_Typedef
* @retval None
* @Example MyI2C_PutString(I2C1,0xAA, &MyI2C_SendTimeData);
* Ecrit dans le slave câblé sur I2C1 à partir de l'@ mémoire interne Slave 0xAA
*/
void MyI2C_PutString(I2C_TypeDef * I2Cx, char PteurAdress, MyI2C_RecSendData_Typedef * DataToSend);
/*=========================================================================================
Réception I2C : GetString
========================================================================================= */
/**
* @brief |Start Cond |@6|@5|@4|@3|@2|@1|@0| Wr =0 |Slave ACK|
|pt7|pt6|pt5|pt4|pt3|pt2|pt1|pt0|Slave ACK|
|ReStart Cond |@6|@5|@4|@3|@2|@1|@0| Wr =1 |Slave ACK|
|d7|d6|d5|d4|d3|d2|d1|d0|Master ACK| (data 1)
.....
|d7|d6|d5|d4|d3|d2|d1|d0|Master NACK|Stop Cond| (data N)
* @param I2Cx: where x can be 1 or 2 to select the I2C peripheral.
* @param PteurAdress = adresse de démarrage lecture à l'interieur du slave I2C
* @param DataToSend, adresse de la structure qui contient les informations nécessaires à la
réception des données voir définition MyI2C_RecSendData_Typedef
* @retval None
* @Example MyI2C_GetString(I2C1,0xAA, &MyI2C_RecevievedTimeData);
Lit dans le slave câblé sur I2C1 à partir de l'@ mémoire interne Slave 0xAA
*/
void MyI2C_GetString(I2C_TypeDef * I2Cx, char PteurAdress, MyI2C_RecSendData_Typedef * DataToReceive);
#endif

129
include/MySPI.h Normal file
View file

@ -0,0 +1,129 @@
#ifndef INC_MYSPI_H_
#define INC_MYSPI_H_
#include "stm32f10x.h"
/*************************************************************************************
===================== By Periph team INSA GEI 2022 ===========================
*************************************************************************************/
/*
*************************************************************************************
===================== I2C les IO STM32F103 =================================
*************************************************************************************
Les IO sont pris en charge par la lib, pas besoin de faire les configurations
Sur la Nucléo , le SPI1 est perturbé par la LED2 (PA5), mais doit pouvoir subir les front SCK qd même (LED clignote vite..)
le SPI2 n'est pas utilisable car pin non connectées par défaut (sauf à modifier les SB). En fait la Nucléo fait un choix entre SPI1
et SPI2 par soudage jumper (SB).
-> Utiliser SPI1 avec la carte Nucléo
* **IO SPI 1**
SPI1_NSS PA4
SPI1_SCK PA5
SPI1_MISO PA6
SPI1_MOSI PA7
**IO SPI 2**
SPI2_NSS PB12
SPI2_SCK PB13
SPI2_MISO PB14
SPI2_MOSI PB15
*************************************************************************************
==================== Fondamentaux SPI ==========================================
*************************************************************************************
- Bus Synchrone, 4 fils (même si on peut l'utiliser en 3 fils)
- Transfert à l'octet
- Protocole entre un Master (contrôle SCK) et un Slave
- SCK permet de synchroniser les bits de chaque octet. Il se configure par :
* son niveau de repos : ici niveau '1'
* le front actif de synchronisation pour chaque bit : ici front montant (front up durant bit stable)
- /CS ou /NSS active le slave sur l'état bas
- MOSI : Master Out Slave In (donc data circulant du Master vers le Slave, donc écriture dans le Slave)
- MISO : Master In Slave Out (donc data circulant du Slave vers le Master, donc lecture du Slave)
Bien que la lib propose une fonction d'écriture et de lecture :
* une écriture s'accompagne obligatoirement d'une lecture (bidon)
* une lecture s'accompagne obligatoirement d'une écriture (bidon)
La gestion /CS = /NSS se fait "à la main". On peut alors lire toute une série d'octets
en laissant /CS à l'état bas pendant toute la durée de circulation des octets.
*************************************************************************************
==================== La lib SPI ==========================================
*************************************************************************************
fonctions essentielles :
MySPI_Init
MySPI_Send
MySPI_Read
MySPI_Set_NSS
MySPI_Clear_NSS
==========================================================================================*/
/*=========================================================================================
INITIALISATION SPI
========================================================================================= */
/**
* @brief Configure le SPI spécifié : FSCK = 281kHz, Repos SCK = '1', Front actif = up
Gestion /CS logicielle à part, configure les 4 IO
- SCK, MOSI : Out Alt push pull
- MISO : floating input
- /NSS (/CS) : Out push pull
* @param SPI_TypeDef * SPI : SPI1 ou SPI2
*/
void MySPI_Init(SPI_TypeDef * SPI);
/**
* @brief Envoie un octet (/CS non géré, à faire logiciellement)
Plus en détail, émission de l'octet souhaité sur MOSI
Lecture en même temps d'un octet poubelle sur MISO (non exploité)
* @param : char ByteToSend : l'octet à envoyer
*/
void MySPI_Send(char ByteToSend);
/**
* @brief Reçoit un octet (/CS non géré, à faire logiciellement)
Plus en détail, émission d'un octet bidon sur MOSI (0x00)
pour élaborer les 8 fronts sur SCK et donc piloter le slave en lecture
qui répond sur MISO
* @param : none
* @retval : l'octet lu.
*/
char MySPI_Read(void);
/**
* @brief Positionne /CS = /NSS à '1'. A utiliser pour borner les octets à transmettre/recevoir
* @param : none
*/
void MySPI_Set_NSS(void);
/**
* @brief Positionne /CS = /NSS à '0'. A utiliser pour borner les octets à transmettre/recevoir
* @param :none
*/
void MySPI_Clear_NSS(void);
#endif

9
include/PWM.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef PWM_H_
#define PWM_H_
#include "stm32f10x.h"
//Variables
#define POWERMODE 2 // 1 vaut powermode 1, 0 vaut powermode 2 (Powermode pour le config de dutycycle)
// Config
extern void MyTimer_PWM(TIM_TypeDef * Timer , int Channel);
extern int Set_DutyCycle_PWM(TIM_TypeDef *Timer, int Channel, int DutyC);
#endif

7
include/Servo.h Normal file
View file

@ -0,0 +1,7 @@
#ifndef SERVO_H_
#define SERVO_H_
#include <stm32f10x.h>
void Servo_Moteur(int angle, TIM_TypeDef * Timer, int Channel);
extern void initServo(TIM_TypeDef * Timer, int Channel);
#endif // SERVO_H_

34
principal.c Normal file
View file

@ -0,0 +1,34 @@
#include <stm32f10x.h>
#include <Horloge.h>
#include <MYGPIO.h>
#include <MySPI.h>
#include <Accelerometre.h>
#include <stdio.h>
#include <Servo.h>
#define ANGLE_LIMITE 60 // Angle ou les voiles seront lachés, SE MODIFIE
volatile uint32_t moy; // Volatile pour pouvoir le regarder dans Keil µVision
uint16_t moyenne[LONGUEUR_MOY];
uint32_t sum;
uint16_t i;
int main (void) {
for (int p = 0; p<LONGUEUR_MOY; p++){moyenne[p]=0xFFFF;} // Initialisation du tableau à 0xFFFF, pour ne pas déclencher immediatement
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // Activation de l'horloge
// Initialisation des modules
initAccelo();
initLacheur();
initServo(TIM4, 3);
while(1){
moyenne[i] = RecupAccelo()[2]; // Récuperation et ajout de la valeur plus récente dans le tableau dans la position i
i++; if (i >= LONGUEUR_MOY) {i = 0;} // Géstion de la position i dans le tableau pour la moyenne glissante
sum = 0; for (int j = 0; j < LONGUEUR_MOY; j++){sum += moyenne[j];} moy = sum / LONGUEUR_MOY; // Calcul de la moyenne glissante
LacheVoile(ANGLE_LIMITE, (uint16_t)moy); // Lache la voile si le bateau dépasse l'angle limite
}
}

58
src/Accelerometre.c Normal file
View file

@ -0,0 +1,58 @@
#include <stm32f10x.h>
#include <Horloge.h>
#include <stdlib.h>
#include <MySPI.h>
#include <stdint.h>
#include <Accelerometre.h>
#include <Servo.h>
void initAccelo(void)
{
MySPI_Init(SPI1);
// Power_CTL register = 0x2D ? write 0x08 (MEASURE = 1)
MySPI_Clear_NSS();
MySPI_Send(0x31); // DATA_FORMAT
MySPI_Send(0b00001101); // Justify met le MSB à gauche et b0 et b1 donne une resolution de +-2g
MySPI_Set_NSS();
MySPI_Clear_NSS();
MySPI_Send(0x2D & 0x3F); // Écriture de l'adresse (pas de bit de read!)
MySPI_Send(0x08); // Affectation du bit MEASURE
MySPI_Set_NSS();
for (volatile int i = 0; i < 10000; i++); // small delay
}
uint16_t * RecupAccelo(void) { // Recuperation des donnees de l'accelerometre
static uint16_t Messie[3];
uint8_t buf[6];
MySPI_Clear_NSS();
// Lecture multi-octet à partir de 0x32 (X0, X1, Y0, Y1, Z0 et Z1)
MySPI_Send(0x80 | 0x40 | 0x32); // On envoie RW MB A5 ... A0 pour recuperer les données
for (int i = 0; i < 6; i++) {buf[i] = (uint8_t)MySPI_Read();} // Lecture des 6 registres en séquenciel
MySPI_Set_NSS();
// Conversion des données récupérés en uint16_t
Messie[0] = (uint16_t)(buf[1] << 8 | buf[0]); // X
Messie[1] = (uint16_t)(buf[3] << 8 | buf[2]); // Y
Messie[2] = (uint16_t)(buf[5] << 8 | buf[4]); // Z
return Messie;
}
void initLacheur(void){
GPIOB->CRH &= ~(0xF << (0 * 4));
GPIOB->CRH |= (0xA << (0 * 4)); //On met GPIOB.8 en mode output 2Mhz, alternate pp
Timer_Init(TIM4, 0xFFFF, 22);
}
void LacheVoile(int AngelLim, uint16_t moyennen){
volatile uint16_t Val_lim = 0x1E20 - 60*AngelLim;
if (moyennen<Val_lim){
Servo_Moteur(0, TIM4, 3); // PB7 (TIM4Ch3)
}
}
// À faire : Gestion par interruption

74
src/DriverGPIO.c Normal file
View file

@ -0,0 +1,74 @@
#include "stm32f10x.h"
#include "DriverGPIO.h"
#define In_Floating 0x4
#define In_PullDown 0x8
#define In_PullUp 0x8
#define In_Analog 0x0
#define Out_Ppull 0x3
#define Out_OD 0x7
#define AltOut_Ppull 0xB
#define AltOut_OD 0xF
void MyGPIO_Init(GPIO_TypeDef * GPIO, char pin, char conf ){
int shift_pin;
//Start clock for relevant GPIO
if(GPIO == GPIOA){
RCC -> APB2ENR |= RCC_APB2ENR_IOPAEN;
}
else if(GPIO == GPIOB){
RCC -> APB2ENR |= RCC_APB2ENR_IOPBEN;
}
else if(GPIO == GPIOC){
RCC -> APB2ENR |= RCC_APB2ENR_IOPCEN;
}
else if(GPIO == GPIOD){
RCC -> APB2ENR |= RCC_APB2ENR_IOPDEN;
}
if(pin < 8){//CRL zone
shift_pin = pin*4;
GPIO -> CRL &= ~(0xF << shift_pin);
//PullUp and PullDown have the same conf number, so we need to change the ODR to diferenciate them both
if(conf == In_PullUp){
GPIO -> CRL |= ( In_PullUp << shift_pin);
GPIO -> ODR |= (1<<pin);
}
else if(conf == In_PullDown){
GPIO -> CRL |= ( In_PullDown << shift_pin);
GPIO -> ODR &= ~(1<<pin);
}
else{
GPIO -> CRL |= ( conf << shift_pin);
}
}
else{//CRH zone
shift_pin = (pin-8)*4;
GPIO -> CRH &= ~(0xF << shift_pin);
if(conf == In_PullUp){
GPIO -> CRH |= ( In_PullUp << shift_pin);
GPIO -> ODR |= (1<<pin);
}
else if(conf == In_PullDown){
GPIO -> CRH |= ( In_PullDown << shift_pin);
GPIO -> ODR &= ~(1<<pin);
}
else{
GPIO -> CRH |= ( conf << shift_pin);
}
}
}
int MyGPIO_Read(GPIO_TypeDef * GPIO, char GPIO_Pin){
return(GPIO -> IDR & (1 << GPIO_Pin));
}
void MyGPIO_Set(GPIO_TypeDef * GPIO, char GPIO_Pin){
GPIO -> BSRR = (1<<GPIO_Pin);//1 on set zone
}
void MyGPIO_Reset(GPIO_TypeDef * GPIO, char GPIO_Pin){
GPIO -> BSRR = (1<<(GPIO_Pin+16));//1 on reset zone
}
void MyGPIO_Toggle(GPIO_TypeDef * GPIO, char GPIO_Pin){
GPIO -> ODR = GPIO -> ODR ^ (0x1 << GPIO_Pin);
}

44
src/Horloge.c Normal file
View file

@ -0,0 +1,44 @@
#include <stm32f10x.h>
#include <Horloge.h>
static void (*TIM2_Appel)(void) = 0;
void Timer_Init(TIM_TypeDef *Timer, unsigned short Autoreload, unsigned short Prescaler){
if (Timer == TIM1) {
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
} else if (Timer == TIM2) {
TIM2->CR1 |= TIM_CR1_CEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
} else if (Timer == TIM3) {
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
} else if (Timer == TIM4) {
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
}
Timer->ARR |= Autoreload;
Timer->PSC |= Prescaler;
Timer->EGR |= TIM_EGR_UG;
}
//La fonction TIM2_IRQHandler existe déjà dans le processeur, on l'a juste redifint, tel qu'à chaque overflow on met un bit 1 dans GPIOA_ODR
void TIM2_IRQHandler(void) { //On redefinit le IRQHandler qui est déjà ecrit dans le code source
if (TIM2->SR & TIM_SR_UIF) { //On met le bit de overflow à un dès qu'on a overflow
TIM2->SR &= ~TIM_SR_UIF; //Remise à zero
if (TIM2_Appel){TIM2_Appel();}
}
}
void MyTimer_ActiveIT(TIM_TypeDef * Timer, char Prio, void(*Interrupt_fonc)(void)){ //On veut créer une fonction qui envoie un signal au cas où il y a debordement, avec une prioritaire, 0 plus importante 15 moins importante
if (Timer == TIM2){
TIM2_Appel = Interrupt_fonc;
NVIC_EnableIRQ(TIM2_IRQn);
NVIC_SetPriority(TIM2_IRQn, Prio);
TIM2->DIER |= TIM_DIER_UIE; //Le registre DIER(Interrupt Enable Register) est mis au bit Update Interrupt, qui se commute lors d'un overflow
TIM2->CR1 |= TIM_CR1_CEN; //Clock Enable
}
}

97
src/MYGPIO.c Normal file
View file

@ -0,0 +1,97 @@
#include <stdlib.h>
#include <stm32f10x.h>
#include <MYGPIO.h>
//FONCTIONS POUR LE DEL INTERNE
void initGPIO_Interne(void){
RCC->APB2ENR |= (0x01 << 2) | (0x01 << 3) | (0x01 << 4) ;
//Start
//CRL pour les 8 premiers portes, CRH pour les 8 dernières portes
if (LED_PIN_INTERNE < 8){
LED_GPIO_INTERNE->CRL &= ~(0xF << (LED_PIN_INTERNE*4));
LED_GPIO_INTERNE->CRL |= GPIO_OUTPUT_PPULL_MODE<<(LED_PIN_INTERNE*4) ; // On met tous les Pins de broche A à ANalog Input sauf broche PA.5 qui correspond au LED GREEN: Output 2MHz et GP output push-pull
}
else{
LED_GPIO_INTERNE->CRH &= ~(0xF <<((LED_PIN_INTERNE-8)*4));
LED_GPIO_INTERNE->CRH |= GPIO_OUTPUT_PPULL_MODE<<((LED_PIN_INTERNE-8)*4);
}
if (BUTTON_PIN_INTERNE < 8){
BUTTON_GPIO_INTERNE->CRL &= ~(0xF << (BUTTON_PIN_INTERNE*4));
BUTTON_GPIO_INTERNE->CRL |= GPIO_INPUT_FLOATING_MODE<<(BUTTON_PIN_INTERNE*4) ; // On met tous les Pins de broche A à ANalog Input sauf broche PA.5 qui correspond au LED GREEN: Output 2MHz et GP output push-pull
}
else{
BUTTON_GPIO_INTERNE->CRH &= ~(0xF <<((BUTTON_PIN_INTERNE-8)*4));
BUTTON_GPIO_INTERNE->CRH |= GPIO_INPUT_FLOATING_MODE<<((BUTTON_PIN_INTERNE-8)*4);
}
}
int boutonAppuye_Interne(void){
return BUTTON_GPIO_INTERNE->IDR &(1<<BUTTON_PIN_INTERNE);
}
void allumerDEL_Interne(void){
LED_GPIO_INTERNE->ODR |= (0x01 << LED_PIN_INTERNE) ; //On essaie de mettre en position PA5 de GPIOC_ODR un 1 comme ca allume le LED GREEN
}
void eteindreDEL_Interne(void){
LED_GPIO_INTERNE->ODR &= ~(0x01 << LED_PIN_EXTERNE) ; //On essaie de mettre en position PA5 de GPIOC_ODR un 0 comme ca eteint le LED GREEN
//ALlumer un LED externe, PB8/D15 OUTPUT, Bouton Poussoir PB9/D14
}
void commuterDEL_Interne(void){
LED_GPIO_INTERNE->ODR ^= (0x01 << LED_PIN_INTERNE);
}
//FONCTIONS POUR LE DEL EXTERNE
void initGPIO_Externe(void){
RCC->APB2ENR |= (0x01 << 2) | (0x01 << 3) | (0x01 << 4) ;
//Start
//CRL pour les 8 premiers portes, CRH pour les 8 dernières portes
if (LED_PIN_EXTERNE < 8){
LED_GPIO_EXTERNE->CRL &= ~(0xF << (LED_PIN_EXTERNE*4));
LED_GPIO_EXTERNE->CRL |= GPIO_OUTPUT_PPULL_MODE<<(LED_PIN_EXTERNE*4) ; // On met tous les Pins de broche A à ANalog Input sauf broche PA.5 qui correspond au LED GREEN: Output 2MHz et GP output push-pull
}
else{
LED_GPIO_EXTERNE->CRH &= ~(0xF <<((LED_PIN_EXTERNE-8)*4));
LED_GPIO_EXTERNE->CRH |= GPIO_OUTPUT_PPULL_MODE<<((LED_PIN_EXTERNE-8)*4);
}
if (BUTTON_PIN_EXTERNE < 8){
BUTTON_GPIO_EXTERNE->CRL &= ~(0xF << (BUTTON_PIN_EXTERNE*4));
BUTTON_GPIO_EXTERNE->CRL |= GPIO_INPUT_FLOATING_MODE<<(BUTTON_PIN_EXTERNE*4) ; // On met tous les Pins de broche A à ANalog Input sauf broche PA.5 qui correspond au LED GREEN: Output 2MHz et GP output push-pull
}
else{
BUTTON_GPIO_EXTERNE->CRH &= ~(0xF <<((BUTTON_PIN_EXTERNE-8)*4));
BUTTON_GPIO_EXTERNE->CRH |= GPIO_INPUT_FLOATING_MODE<<((BUTTON_PIN_EXTERNE-8)*4);
}
}
int boutonAppuye_Externe(void){
return BUTTON_GPIO_EXTERNE->IDR &(1<<BUTTON_PIN_EXTERNE);
}
void allumerDEL_Externe(void){
LED_GPIO_EXTERNE->ODR |= (0x01 << LED_PIN_EXTERNE) ;
} //On essaie de mettre en position PA5 de GPIOC_ODR un 1 comme ca allume le LED GREEN
void eteindreDEL_Externe(void){
LED_GPIO_EXTERNE->ODR &= ~(0x01 << LED_PIN_EXTERNE) ; //On essaie de mettre en position PA5 de GPIOC_ODR un 0 comme ca eteint le LED GREEN
//ALlumer un LED externe, PB8/D15 OUTPUT, Bouton Poussoir PB9/D14
}
void commuterDEL_Externe(void){
LED_GPIO_EXTERNE->ODR ^= (0x01 << LED_PIN_EXTERNE);
}

85
src/PWM.c Normal file
View file

@ -0,0 +1,85 @@
#include "stm32f10x.h"
#include "PWM.h"
void MyTimer_PWM(TIM_TypeDef * Timer , int Channel){
int pwrmd;
#if POWERMODE //Powermode 1
pwrmd = 0b110;
#else
pwrmd = 0b111; //Powermode 2
#endif
if (Channel == 1){
Timer->CCMR1 &= ~(0b111<<4); //On clear les trois bits qui sont de pwm
Timer->CCMR1 |= (pwrmd<<4); //On affecte le powermode au bits de lecture pour le µ-controlleur
Timer->CCMR1 |= TIM_CCMR1_OC1PE; //Update preload, il n'affecte pas le valeur avant que la prochaine cycle
Timer->CCER = TIM_CCER_CC1E; //Enable le pin voulu basculer
}
else if (Channel == 2){
Timer->CCMR1 &= ~(0b111<<12); //Le TIMx_CCMR1 configure deux channels, de bit [6:4] CH1, [14:12] CH2 (OC2M = Output Channel 2 )
Timer->CCMR1 |= (pwrmd<<12);
Timer->CCMR1 |= TIM_CCMR1_OC2PE;
Timer->CCER |= TIM_CCER_CC2E;
}
else if (Channel == 3){
Timer->CCMR1 &= ~(0b111<<4);
Timer->CCMR2 |= (pwrmd<<4);
Timer->CCMR2 |= TIM_CCMR2_OC3PE;
Timer->CCER |= TIM_CCER_CC3E;
}
else if (Channel == 4){
Timer->CCMR1 &= ~(0b111<<12);
Timer->CCMR2 |= (pwrmd<<12);
Timer->CCMR2 |= TIM_CCMR2_OC4PE;
Timer->CCER |= TIM_CCER_CC4E;
}
//En dessous d'ici, on a l'aide du plus gentil chat que je connais
// Enable auto-reload preload -- //Ensures that your initial configuration — PWM mode, duty cycle, period — actually takes effect before the timer starts counting.
Timer->CR1 |= TIM_CR1_ARPE;
// Force update event to load ARR and CCR values immediately
Timer->EGR |= TIM_EGR_UG;
// Start the timer
Timer->CR1 |= TIM_CR1_CEN;
switch (Channel) {
case 1:
if (Timer == TIM1){GPIOA->CRH &= ~(0xF<<0*4); GPIOA->CRH |= (0xA<<0*4); TIM1->BDTR |= 1<<15; }
if (Timer == TIM2){GPIOA->CRL &= ~(0xF<<0*4); GPIOA->CRL |= (0xA<<0*4);}
if (Timer == TIM3){GPIOA->CRL &= ~(0xF<<6*4); GPIOA->CRL |= (0xA<<6*4);}
if (Timer == TIM4){GPIOB->CRL &= ~(0xF<<5*4); GPIOB->CRL |= (0xA<<5*4);}
break;
case 2:
if (Timer == TIM1){GPIOA->CRH &= ~(0xF<<1*4); GPIOA->CRL |= (0xA<<1*4); TIM1->BDTR |= 1<<15;}
if (Timer == TIM2){GPIOA->CRL &= ~(0xF<<1*4); GPIOA->CRL |= (0xA<<1*4);}
if (Timer == TIM3){GPIOA->CRL &= ~(0xF<<7*4); GPIOA->CRL |= (0xA<<7*4);}
if (Timer == TIM4){GPIOB->CRL &= ~(0xF<<7*4); GPIOB->CRL |= (0xA<<7*4);}
break;
case 3:
if (Timer == TIM1){GPIOA->CRH &= ~(0xF<<2*4); GPIOA->CRH |= (0xA<<2*4); TIM1->BDTR |= 1<<15;}
if (Timer == TIM2){GPIOA->CRL &= ~(0xF<<2*4); GPIOA->CRL |= (0xA<<2*4);}
if (Timer == TIM3){GPIOB->CRL &= ~(0xF<<0*4); GPIOB->CRL |= (0xA<<0*4);}
if (Timer == TIM4){GPIOB->CRH &= ~(0xF<<0*4); GPIOB->CRH |= (0xA<<0*4);}
break;
case 4:
if (Timer == TIM1){GPIOA->CRH &= ~(0xF<<3*4); GPIOA->CRH |= (0xA<<3*4); TIM1->BDTR |= 1<<15;}
if (Timer == TIM2){GPIOA->CRL &= ~(0xF<<3*4); GPIOA->CRL |= (0xA<<3*4);}
if (Timer == TIM3){GPIOB->CRL &= ~(0xF<<1*4); GPIOB->CRL |= (0xA<<1*4);}
if (Timer == TIM4){GPIOB->CRH &= ~(0xF<<1*4); GPIOB->CRH |= (0xA<<1*4);}
}
}
//Une fonction qui met le bon PWM voulu
int Set_DutyCycle_PWM(TIM_TypeDef *Timer, int Channel, int DutyC){
int CCR_VAL = (Timer -> ARR + 1) * DutyC / 100;
switch (Channel){
case 1: Timer->CCR1 = CCR_VAL;
case 2: Timer->CCR2 = CCR_VAL;
case 3: Timer->CCR3 = CCR_VAL;
case 4: Timer->CCR4 = CCR_VAL;
default: break;
}
return 0;
Timer->EGR |= TIM_EGR_UG;
}

27
src/Servo.c Normal file
View file

@ -0,0 +1,27 @@
#include <Servo.h>
#include <DriverGPIO.h>
#include <PWM.h>
#include <Horloge.h>
void Servo_Moteur(int angle, TIM_TypeDef * Timer, int Channel){ // Controle du moteur
int dutyCycle = (5* angle + 5*90)/90; // 5-10 % Duty Cycle
Set_DutyCycle_PWM(Timer, Channel, dutyCycle);
}
void initServo(TIM_TypeDef * Timer, int Channel){ // Config du moteur servo
if (Timer == TIM4) {
Timer_Init(TIM4, 0xFFFF, 22); // Pour obtenir un période de 20 ms
if (Channel == 3){
MyGPIO_Init(GPIOB, 8, AltOut_Ppull); // Outut push pull alternate
MyTimer_PWM(TIM4, 3); //TIM4 CH3 pour PB8
}
else{
//printf("Cet pilôte n'existe pas");
}
}
else{
//printf("Cet pilôte n'existe pas");
}
}