Ajout de beacoup de code pour gérér l'acceleromètre par SPI. Code à revoir
This commit is contained in:
parent
63fc720afa
commit
f4ed19452d
17 changed files with 1185 additions and 8 deletions
16
include/Accelerometre.h
Normal file
16
include/Accelerometre.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#include <stm32f10x.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define LONGUEUR_MOY 10
|
||||
#define ANGLE 20 //Degs
|
||||
#define MIN 1
|
||||
#define MODEAVANCEE 1
|
||||
#define OSKAR 0
|
||||
|
||||
void initAccelo(void);
|
||||
uint16_t * RecupAccelo(void);
|
||||
void LacheVoile(uint16_t voile_moy);
|
||||
void LacheVoileNew(void);
|
||||
void initLacheur(void);
|
||||
uint16_t * KattRecupAccelo(void);
|
||||
void LacheVoileSmart(int AngelLim, uint16_t moyennen);
|
||||
17
include/DriverGPIO.h
Normal file
17
include/DriverGPIO.h
Normal 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
16
include/Horloge.h
Normal 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
38
include/MYGPIO.h
Normal 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
229
include/MyI2C.h
Normal 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
129
include/MySPI.h
Normal 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
9
include/PWM.h
Normal 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
7
include/Servo.h
Normal 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_
|
||||
8
include/Timer.h
Normal file
8
include/Timer.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef TIMER_H_
|
||||
#define TIMER_H_
|
||||
#include <stm32f10x.h>
|
||||
// Config de timer
|
||||
extern void MyTimer_Base_Init(TIM_TypeDef *Timer , unsigned short ValARR , unsigned short ValPSC );
|
||||
// Enable timers
|
||||
void EnableTimer(TIM_TypeDef *Timer);
|
||||
#endif
|
||||
64
principal.c
64
principal.c
|
|
@ -4,27 +4,75 @@
|
|||
#include <MySPI.h>
|
||||
#include <Accelerometre.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#include <Servo.h>
|
||||
|
||||
uint16_t * Melding;
|
||||
volatile uint16_t X;
|
||||
volatile uint16_t Y;
|
||||
volatile uint16_t Z;
|
||||
volatile uint32_t moy;
|
||||
//volatile uint16_t Angle_lim = 0x1500;
|
||||
|
||||
int main ( void )
|
||||
{
|
||||
//RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; //Broder!!! Hvorfor var ikke den linjen kode her! Var Brage btw som fjernet den. Ingenting skjer hvis selve clocken ikke er på!
|
||||
volatile uint16_t Angle_lim = 0x1E20 - 60*ANGLE; //#define ANGLE_LIMITE 0x0E38
|
||||
int main (void) {
|
||||
#if MIN
|
||||
int i = 0;
|
||||
|
||||
uint32_t moyenne[LONGUEUR_MOY];
|
||||
for (int p = 0; p<LONGUEUR_MOY; p++){moyenne[p]=0xFFFF;}
|
||||
|
||||
|
||||
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; //Broder!!! Hvorfor var ikke den linjen kode her! Var Brage btw som fjernet den. Ingenting skjer hvis selve clocken ikke er på!
|
||||
initAccelo();
|
||||
initLacheur();
|
||||
//initLacheur();
|
||||
initServo(TIM4, 3);
|
||||
|
||||
while(1){
|
||||
Melding = KattRecupAccelo();
|
||||
LacheVoile(Melding);
|
||||
Melding = KattRecupAccelo(); //Recuperation des données de l'acceleromètre
|
||||
moyenne[i] = Melding[2]; //Ajout de la valeur recuperée à la moyenne
|
||||
i++; if (i>LONGUEUR_MOY) {i=0;} //itération
|
||||
moy = 0; for(int j = 0; j<LONGUEUR_MOY;j++){moy += moyenne[j];} moy = moy/LONGUEUR_MOY; //Calcul de la moyenne glissante
|
||||
//LacheVoile((uint16_t)moy); //Envoi de valeur
|
||||
//if (moy<Angle_lim){LacheVoileNew();}
|
||||
|
||||
//################
|
||||
LacheVoileSmart(50, (uint16_t)moy);
|
||||
|
||||
//Juste pour essayer de regarder ce que ça affiche
|
||||
X=Melding[0];
|
||||
Y=Melding[1];
|
||||
Z=Melding[2];
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
while(1){
|
||||
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; //Broder!!! Hvorfor var ikke den linjen kode her! Var Brage btw som fjernet den. Ingenting skjer hvis selve clocken ikke er på!
|
||||
initAccelo();
|
||||
initLacheur();
|
||||
|
||||
uint32_t moyenne[LONGUEUR_MOY] = {0}; // initialize to 0
|
||||
int i = 0;
|
||||
|
||||
Melding = KattRecupAccelo();
|
||||
|
||||
moyenne[i] = Melding[2]; // add newest Z
|
||||
i++;
|
||||
if (i >= LONGUEUR_MOY)i = 0; // wrap around properly
|
||||
|
||||
uint32_t sum = 0;
|
||||
for (int j = 0; j < LONGUEUR_MOY; j++){
|
||||
sum += moyenne[j];
|
||||
}
|
||||
moy = sum / LONGUEUR_MOY; // moving average
|
||||
|
||||
LacheVoile((uint16_t)moy);
|
||||
|
||||
X = Melding[0];
|
||||
Y = Melding[1];
|
||||
Z = Melding[2];
|
||||
}
|
||||
#endif
|
||||
while(1);
|
||||
}
|
||||
|
||||
|
|
|
|||
185
src/Accelerometre.c
Normal file
185
src/Accelerometre.c
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
#include <stm32f10x.h>
|
||||
#include <Horloge.h>
|
||||
#include <MYGPIO.h>
|
||||
#include <stdlib.h>
|
||||
#include <MySPI.h>
|
||||
#include <stdint.h>
|
||||
#include <Accelerometre.h>
|
||||
#include <stdio.h>
|
||||
#include <Timer.h>
|
||||
#include <Servo.h>
|
||||
|
||||
//Pin GPIOA_9 et GPIOA_10 sont pris par USART
|
||||
|
||||
/*
|
||||
I2C SDA IN/OUT
|
||||
I2C SCL OUT
|
||||
*/
|
||||
|
||||
//il faut recuperer le data qui sort
|
||||
|
||||
/*
|
||||
SPI1_NSS PA4 - Utilisé
|
||||
NSS = 0 -> slave active
|
||||
NSS = 1 -> slave inactive
|
||||
|
||||
SPI1_SCK PA5
|
||||
SPI1_MISO PA6
|
||||
SPI1_MOSI PA7
|
||||
|
||||
TIM3 CH3 PB0
|
||||
|
||||
0x32 50 DATAX0 R 00000000 X-Axis Data 0
|
||||
0x33 51 DATAX1 R 00000000 X-Axis Data 1
|
||||
0x34 52 DATAY0 R 00000000 Y-Axis Data 0
|
||||
0x35 53 DATAY1 R 00000000 Y-Axis Data 1
|
||||
0x36 54 DATAZ0 R 00000000 Z-Axis Data 0
|
||||
0x37 55 DATAZ1 R 00000000 Z-Axis Data 1
|
||||
|
||||
*/
|
||||
|
||||
|
||||
void initAccelo(void)
|
||||
{
|
||||
MySPI_Init(SPI1);
|
||||
|
||||
// Power_CTL register = 0x2D ? write 0x08 (MEASURE = 1)
|
||||
MySPI_Clear_NSS();
|
||||
MySPI_Send(0x31);
|
||||
MySPI_Send(0b00001101); //Justify met MSB à gauche et b0 et b1 donne resolution en +-2g
|
||||
MySPI_Set_NSS();
|
||||
|
||||
MySPI_Clear_NSS();
|
||||
MySPI_Send(0x2D & 0x3F); // write address (no read bit!)
|
||||
MySPI_Send(0x08); // set MEASURE bit
|
||||
MySPI_Set_NSS();
|
||||
|
||||
for (volatile int i = 0; i < 10000; i++); // small delay
|
||||
}
|
||||
|
||||
// send bits, les bits inclus en char envoyés: RW MB A5 A4 A3 A2 A1 A0
|
||||
//RW: R = 1 et W = 0
|
||||
//MB à 1 veut measurement et MB à 0 Standby
|
||||
uint16_t * RecupAccelo(void){ //Renvoie 48 bits en forme des chars
|
||||
static uint16_t Messias[3];
|
||||
|
||||
//On lit X0
|
||||
MySPI_Clear_NSS();//Mettre la broche PA4 à 0
|
||||
MySPI_Send(0x80|0x00|0x32); //Lecture de X0 et MB à 1 pour garder les valeurs 0b11110010: (R/W|MB|Adress)
|
||||
//Faktisk dritsmart det katten gjør, setter MB=1 som sier multiple byte read, så leser den alle 6 bytes samtidig istedenfor en og en
|
||||
uint16_t X0 = MySPI_Read();
|
||||
MySPI_Set_NSS(); //Mettre la broche PA4 à 1
|
||||
|
||||
//On lit X1
|
||||
MySPI_Clear_NSS();//Mettre la broche PA4 à 0
|
||||
MySPI_Send(0x80|0x00|0x33); //Lecture de X1
|
||||
Messias[0] = X0 | (MySPI_Read() << 8);
|
||||
MySPI_Set_NSS(); //Mettre la broche PA4 à 1
|
||||
|
||||
//On lit Y0
|
||||
MySPI_Clear_NSS();//Mettre la broche PA4 à 0
|
||||
MySPI_Send(0x80|0x00|0x34); //Lecture de Y0
|
||||
uint16_t Y0 = MySPI_Read();
|
||||
MySPI_Set_NSS(); //Mettre la broche PA4 à 1
|
||||
|
||||
//On lit Y1
|
||||
MySPI_Clear_NSS();//Mettre la broche PA4 à 0
|
||||
MySPI_Send(0x80|0x00|0x35); //Lecture de Y1
|
||||
Messias[1] = Y0 | (MySPI_Read() << 8);
|
||||
MySPI_Set_NSS(); //Mettre la broche PA4 à 1
|
||||
|
||||
//On lit Z0
|
||||
MySPI_Clear_NSS();//Mettre la broche PA4 à 0
|
||||
MySPI_Send(0x80|0x00|0x36); //Lecture de Z0
|
||||
uint16_t Z0 = MySPI_Read();
|
||||
MySPI_Set_NSS(); //Mettre la broche PA4 à 1
|
||||
|
||||
//On lit Z1
|
||||
MySPI_Clear_NSS();//Mettre la broche PA4 à 0
|
||||
MySPI_Send(0x80|0x00|0x37); //Lecture de Z1
|
||||
Messias[2] = Z0 | (MySPI_Read() << 8);
|
||||
MySPI_Set_NSS(); //Mettre la broche PA4 à 1
|
||||
|
||||
return Messias;
|
||||
}
|
||||
|
||||
|
||||
uint16_t * KattRecupAccelo(void) //Beaucoup plus smart
|
||||
{
|
||||
static uint16_t Messias[3];
|
||||
uint8_t buf[6];
|
||||
// Multi-byte read from 0x32 (X0..Z1)
|
||||
MySPI_Clear_NSS();
|
||||
// Send READ + MB + address
|
||||
MySPI_Send(0x80 | 0x40 | 0x32); // 0xF2
|
||||
// Read 6 sequential registers
|
||||
for (int i = 0; i < 6; i++) {
|
||||
buf[i] = (uint8_t)MySPI_Read();
|
||||
}
|
||||
MySPI_Set_NSS();
|
||||
// Convert little-endian to 16-bit signed values
|
||||
Messias[0] = (uint16_t)(buf[1] << 8 | buf[0]); // X
|
||||
Messias[1] = (uint16_t)(buf[3] << 8 | buf[2]); // Y
|
||||
Messias[2] = (uint16_t)(buf[5] << 8 | buf[4]); // Z
|
||||
|
||||
return Messias;
|
||||
}
|
||||
|
||||
void initLacheur(void){
|
||||
GPIOB->CRH &= ~(0xF << (0 * 4));
|
||||
GPIOB->CRH |= (0xA << (0 * 4)); //On met GPIOB.8 en mode output 2Mhz, alternate pp
|
||||
#if OSKAR
|
||||
EnableTimer(TIM4);
|
||||
MyTimer_Base_Init(TIM4, 0xFFFF, 22);
|
||||
#else
|
||||
Timer_Init(TIM4, 20000 - 1, 71); //Claire m'a aidé
|
||||
#endif
|
||||
}
|
||||
|
||||
//Recuperer le DATA en X, Z, Y
|
||||
#if MODEAVANCEE
|
||||
//volatile uint16_t Angle_lim = 0x1E20 - 60*ANGLE; //#define ANGLE_LIMITE 0x0E38
|
||||
#else
|
||||
volatile uint16_t Anngle_lim = 0x1500;
|
||||
#endif
|
||||
/*
|
||||
void LacheVoile(uint16_t voile_moy){
|
||||
if (voile_moy<=Anngle_lim){// exatement à 40 degrés, on lache le 40%. 0xFF*(40deg/90deg)
|
||||
//Le PWM du moteur est gère par PB7
|
||||
MyTimer_PWM(TIM4, 3); //TIM4 CH3 pour PB8
|
||||
Set_DutyCycle_PWM(TIM4, 3, 5); //On met Duty cycle à 2% et il reste autour de 90 deg
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void LacheVoileNew(){
|
||||
// exatement à 40 degrés, on lache le 40%. 0xFF*(40deg/90deg)
|
||||
//Le PWM du moteur est gère par PB7
|
||||
|
||||
Servo_Moteur(0, TIM4, 3);
|
||||
}
|
||||
|
||||
void LacheVoileSmart(int AngelLim, uint16_t moyennen){
|
||||
volatile uint16_t Val_lim = 0x1E20 - 60*AngelLim;
|
||||
// exatement à 40 degrés, on lache le 40%. 0xFF*(40deg/90deg)
|
||||
//Le PWM du moteur est gère par PB7
|
||||
if (moyennen<Val_lim){
|
||||
Servo_Moteur(0, TIM4, 3);
|
||||
}
|
||||
}
|
||||
|
||||
//Gestion de l'interruption
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
74
src/DriverGPIO.c
Normal file
74
src/DriverGPIO.c
Normal 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);
|
||||
}
|
||||
163
src/Horloge.c
Normal file
163
src/Horloge.c
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
#include <stm32f10x.h>
|
||||
#include <stdio.h>
|
||||
#include <Horloge.h>
|
||||
|
||||
|
||||
//Il faut trouver le signal
|
||||
//On est à Timer 2
|
||||
|
||||
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; //L'horloge est enabléd
|
||||
} else if (Timer == TIM2) {
|
||||
TIM2->CR1 |= TIM_CR1_CEN; //On enable l'horloge interne
|
||||
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;
|
||||
}
|
||||
|
||||
//La fonction TIM2_IRQHandler s'utilise 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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Fonction qui permet de clignoter le DEL à un pulse volue (Sinusoïdale)
|
||||
//Si le sinus est haut(haute tension) le Duty Cicle est proche de 100%,
|
||||
//si le sinus est bas (vers la tension la plus basse) le Duty Cycle est vers 0%
|
||||
//On s'applique sur un plage de [0V; 3.3V]
|
||||
|
||||
|
||||
/*
|
||||
|
||||
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 volue
|
||||
int Set_DutyCycle_PWM(TIM_TypeDef *Timer, int Channel, int DutyC){
|
||||
int CCR_VAL = (ARR_VAL + 1) * DutyC / 100; //ARR_VAL déjà definie
|
||||
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;
|
||||
}
|
||||
|
||||
*/
|
||||
//Putaing con, ça marche pas
|
||||
|
||||
|
||||
/*
|
||||
Pulse width modulation mode allows you to generate a signal with a frequency determined
|
||||
by the value of the TIMx_ARR register and a duty cycle determined by the value of the
|
||||
TIMx_CCRx register.
|
||||
|
||||
The PWM mode can be selected independently on each channel (one PWM per OCx
|
||||
output) by writing 110 (PWM mode 1) or ‘111 (PWM mode 2) in the OCxM bits in the
|
||||
TIMx_CCMRx register. You must enable the corresponding preload register by setting the
|
||||
OCxPE bit in the TIMx_CCMRx register, and eventually the auto-reload preload register by
|
||||
setting the ARPE bit in the TIMx_CR1 register.
|
||||
*/
|
||||
//Il faut créer une autre fonction qui lui met le bon duty cycle
|
||||
//Timer->CCR1 = Duty_cycle*0.01*3.3; // On divise par cent et multiplue par 3.3V, plage de ADC
|
||||
|
||||
//Pareil pour la frequence, faut une fonction externe qui lui fait ça
|
||||
|
||||
|
||||
//Pendant les vacances terminer l'ADC et l'USART (Activités sur Moodle)
|
||||
//Hell naw, that did not happen cuh
|
||||
|
||||
97
src/MYGPIO.c
Normal file
97
src/MYGPIO.c
Normal 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
85
src/PWM.c
Normal 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;
|
||||
}
|
||||
29
src/Servo.c
Normal file
29
src/Servo.c
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#include <Servo.h>
|
||||
#include <DriverGPIO.h>
|
||||
#include <PWM.h>
|
||||
#include <Timer.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) {
|
||||
EnableTimer(TIM4);
|
||||
//MyTimer_Base_Init(TIM4, 20000 - 1, 71);
|
||||
MyTimer_Base_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");
|
||||
}
|
||||
}
|
||||
|
||||
27
src/Timer.c
Normal file
27
src/Timer.c
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#include <stm32f10x.h>
|
||||
#include <Timer.h>
|
||||
|
||||
void MyTimer_Base_Init( TIM_TypeDef * Timer , unsigned short ValARR , unsigned short ValPSC ) { // Configuration du timer
|
||||
Timer -> PSC=(ValPSC);
|
||||
Timer-> ARR = (ValARR);
|
||||
Timer->EGR |= TIM_EGR_UG;
|
||||
};
|
||||
|
||||
|
||||
|
||||
void EnableTimer(TIM_TypeDef *Timer){
|
||||
if(Timer == TIM2){
|
||||
RCC -> APB1ENR |= RCC_APB1ENR_TIM2EN;
|
||||
}
|
||||
else if(Timer == TIM3){
|
||||
RCC -> APB1ENR |= RCC_APB1ENR_TIM3EN;
|
||||
}
|
||||
else if(Timer == TIM4){
|
||||
RCC -> APB1ENR |= RCC_APB1ENR_TIM4EN;
|
||||
}
|
||||
else if(Timer == TIM1){
|
||||
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
|
||||
}
|
||||
else{
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue