« Micro contrôleurs AVR/Travail pratique/Télécommande NRF24L01 pour Robot » : différence entre les versions

Contenu supprimé Contenu ajouté
Ligne 687 :
 
=== Exercice 6 ===
 
 
{{Solution|contenu=
'''!!!!Nous donnons pour l'instant une solution précaire mais fonctionnelle qui sera remaniée plus tard !!!!!!!'''
<syntaxhighlight lang="C">
#include <avr/io.h>
#include <avr/sfr_defs.h>
#include <util/delay.h>
 
#define F_CPU 16000000 // 16 MHz oscillator.
#define BaudRate 9600
#define MYUBRR (F_CPU / 16 / BaudRate ) - 1
 
void serialInit(void) {
//Serial Initialization
/*Set baud rate 9600 */
UBRR0H = (unsigned char)(MYUBRR>>8);
UBRR0L = (unsigned char) MYUBRR;
/* Enable receiver and transmitter */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Frame format: 8data, No parity, 1stop bit */
UCSR0C = ((1<<UCSZ01)|(1<<UCSZ00)); // seulement deux bits à configurer
}
 
void serialWrite(uint8_t DataOut) {
loop_until_bit_is_set(UCSR0A,UDRE0); // while NOT ready to transmit
UDR0 = DataOut;
}
 
void serialWrite8Deci(uint8_t DataOut) {
uint8_t tab[3];
tab[0] = DataOut / 100 + '0';
tab[1] = ((DataOut / 10) % 10) + '0';
tab[2] = (DataOut % 10) + '0';
serialWrite(tab[0]); // centaine
serialWrite(tab[1]); // dizaine
serialWrite(tab[2]); // unité
}
 
void serialWrite16Deci(uint16_t DataOut) {
uint8_t tab[4]; // on se limite à 4 car CAN ne dépasse pas 1023
tab[0] = DataOut / 1000 + '0';
tab[1] = ((DataOut / 100) % 10) + '0';
tab[2] = ((DataOut /10)% 10) + '0';
tab[3] = (DataOut % 10) + '0';
serialWrite(tab[0]); // millier
serialWrite(tab[1]); // centaine
serialWrite(tab[2]); // dizaine
serialWrite(tab[3]); // unité
}
 
void ADC_Init(void) {
// Choose AVCC pin for the comparison voltage
ADMUX = (1 << REFS0) ;
// Start the ADC unit,
// set the conversion cycle 16 times slower than the duty cycle
ADCSRA = (1 << ADEN) | (1 << ADPS2);
}
 
uint16_t ADC_get(uint8_t channel) {
// Choose channel in the multiplexer
ADMUX &= 0xF0; // (MUX3,MUX2,MUX1,MUX0) = (0,0,0,0)
ADMUX |= (channel & 0x0F) << MUX0; //on veut channel<16
// on lance la conversion
ADCSRA |= (1 << ADSC);
// on attend qu'elle soit finie
loop_until_bit_is_clear(ADCSRA, ADSC);
// ici le bit ADSC vient de passer à 0
return ADC;
}
 
//SPI init
void SPIMasterInit(void) {
uint8_t data;
//set MOSI, SCK and CSN as output
DDRB |= (1<<PB3)|(1<<PB5);
DDRD |= (1<<PD7); // CSN
PORTB |= (1<<PB2); //set SS to high (pullup)
_delay_ms(1); // le passage en pull-up n'est pas instantané
//enable master SPI at clock rate Fck/16
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
//set CSN to high
PORTD |= (1<<PD7);
_delay_ms(1);
// clear SPIF
data = SPSR;
data = SPDR;
}
 
//master send function
void SPIMasterSend(uint8_t data){
//select slave
PORTD &= ~(1<<PD7); // CSN
//send data
SPDR=data;
//wait for transmition complete
loop_until_bit_is_set(SPSR, SPIF);
//CSN to high
PORTD |= (1<<PD7);
}
 
//********** On spécialise le SPI pour le NRF24L01 ***********
// ne gère pas CSN
uint8_t SPI_NRF24_RW(uint8_t data) {
SPDR=data;
loop_until_bit_is_set(SPSR, SPIF);
return SPDR;
}
 
// écriture d'une valeur dans un registre : ajouter W_REGISTER dans reg
uint8_t SPI_NRF24_W_Reg(uint8_t reg, uint8_t value) {
uint8_t status;
//CSN to LOW
PORTD &= ~(1<<PD7);
status = SPI_NRF24_RW(reg);
SPI_NRF24_RW(value);
//CSN to high
PORTD |= (1<<PD7);
return(status);
}
 
// Lecture de données d'un registre
uint8_t SPI_NRF24_R_Reg_Buf(uint8_t reg, uint8_t *pBuf, uint8_t bytes)
{
uint8_t status1,uchar_ctr;
//CSN to LOW
PORTD &= ~(1<<PD7);
status1 = SPI_NRF24_RW(reg);
for(uchar_ctr=0;uchar_ctr<bytes;uchar_ctr++)
pBuf[uchar_ctr] = SPI_NRF24_RW(0);
//CSN to high
PORTD |= (1<<PD7);
return(status1);
}
 
// Ecriture de données dans un registre
uint8_t SPI_NRF24_W_Reg_Buf(uint8_t reg, uint8_t *pBuf, uint8_t bytes)
{
uint8_t status1,uchar_ctr;
//CSN to LOW
PORTD &= ~(1<<PD7);
status1 = SPI_NRF24_RW(reg);
for(uchar_ctr=0; uchar_ctr<bytes; uchar_ctr++) //
SPI_NRF24_RW(*pBuf++);
//CSN to high
PORTD |= (1<<PD7);
return(status1); //
}
 
//#include "nRF24L01.h"
#define CONFIG 0x00
#define EN_AA 0x01
#define EN_RXADDR 0x02
#define SETUP_AW 0x03
#define SETUP_RETR 0x04
#define RF_CH 0x05
#define RF_SETUP 0x06
#define STATUS 0x07
#define OBSERVE_TX 0x08
#define CD 0x09
#define RX_ADDR_P0 0x0A
#define RX_ADDR_P1 0x0B
#define RX_ADDR_P2 0x0C
#define RX_ADDR_P3 0x0D
#define RX_ADDR_P4 0x0E
#define RX_ADDR_P5 0x0F
#define TX_ADDR 0x10
#define RX_PW_P0 0x11
#define RX_PW_P1 0x12
#define RX_PW_P2 0x13
#define RX_PW_P3 0x14
#define RX_PW_P4 0x15
#define RX_PW_P5 0x16
#define FIFO_STATUS 0x17
/* Instruction Mnemonics */
#define R_REGISTER 0x00
#define W_REGISTER 0x20
#define REGISTER_MASK 0x1F
#define R_RX_PAYLOAD 0x61
#define W_TX_PAYLOAD 0xA0
#define FLUSH_TX 0xE1
#define FLUSH_RX 0xE2
#define REUSE_TX_PL 0xE3
#define NOP 0xFF
 
#define TX_ADR_WIDTH 5 // send address length, the maxium length is 5 5*8=40 bit
#define RX_ADR_WIDTH 5 // receive date length
#define TX_PLOAD_WIDTH 4 // send bytes length
#define RX_PLOAD_WIDTH 4 // Receive bytes length
uint8_t TX_ADDRESS[TX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //send address
uint8_t RX_ADDRESS[RX_ADR_WIDTH]={'s','e','r','v','1'}; //receive address
 
void SetRX_Mode(void)
{
// gestion de CE en PB0
DDRB |= (1<<PB0);
//CE to LOW
PORTB &= ~(1<<PB0);
SPI_NRF24_W_Reg_Buf(W_REGISTER + RX_ADDR_P1, RX_ADDRESS, RX_ADR_WIDTH); //write receive address
SPI_NRF24_W_Reg_Buf(W_REGISTER + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); //write transmit address
SPI_NRF24_W_Reg(W_REGISTER + RF_CH,1); //RF channel
SPI_NRF24_W_Reg(W_REGISTER + RX_PW_P0, RX_PLOAD_WIDTH);//write channel 0 receive data length
SPI_NRF24_W_Reg(W_REGISTER + RX_PW_P1, RX_PLOAD_WIDTH);//write channel 1 receive data length
// Start receiver
SPI_NRF24_W_Reg(W_REGISTER + CONFIG, 0x0B); //receive mode :EN_CRC,PWR_UP, PRIM_RX
//CE to HIGH
PORTB |= (1<<PB0);
_delay_ms(1);//can't be too small
#define TX_DS 5
#define MAX_RT 4
SPI_NRF24_W_Reg(W_REGISTER + STATUS,(1 << TX_DS) | (1 << MAX_RT));
//Instruction : flushRx
SPIMasterSend(FLUSH_RX);
}
 
uint8_t SPI_NRF24_R_Reg(uint8_t reg) //OK
{
uint8_t reg_val;
//CSN to LOW
PORTD &= ~(1<<PD7);
SPI_NRF24_RW(reg);
reg_val = SPI_NRF24_RW(0);
//CSN to high
PORTD |= (1<<PD7);
return(reg_val);
}
 
uint8_t nRF24L01_RxPacket(uint8_t* rx_buf)
{
uint8_t status1;
status1=SPI_NRF24_R_Reg_Buf(R_RX_PAYLOAD,rx_buf,TX_PLOAD_WIDTH);// read receive payload from RX_FIFO buffer
#define RX_DR 6
SPI_NRF24_W_Reg(W_REGISTER+STATUS,(1<<RX_DR));
return status1;
}
 
int main() {
uint16_t joystick_x,joystick_y;
uint8_t rx_buffer[RX_PLOAD_WIDTH],status1,cmpt=0;
// setup
serialInit();
//ADC_Init();
SPIMasterInit();
SetRX_Mode();
// loop
while (1) {
status1=nRF24L01_RxPacket(rx_buffer);
if (status1 & (1<<RX_DR)) {
joystick_x = (rx_buffer[1]<<8)+rx_buffer[0];
joystick_y = (rx_buffer[3]<<8)+rx_buffer[2];
serialWrite16Deci(joystick_x);
serialWrite(' ');serialWrite('-');serialWrite(' ');
serialWrite16Deci(joystick_y);
serialWrite(0x0D);serialWrite(0x0A);
} else {
serialWrite('*');serialWrite('*');
serialWrite(0x0D);serialWrite(0x0A);
}
}
}
 
</syntaxhighlight>
}}
 
==Réalisation et programmation de la télécommande==