⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mcu_atmega48_88.c

📁 nrf24z1 代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*= mcu_atmega48_88.c ==========================================================
 *
 * Copyright (C) 2005 Nordic Semiconductor
 *
 * This file is distributed in the hope that it will be useful, but WITHOUT
 * WARRANTY OF ANY KIND.
 *
 * Author(s): Borge Strand
 *
 * Description:
 *
 *    MCU specific code for Atmel ATmega48 and ATmega88
 *    This file must be ported to any other MCU to be used. 
 *    It must implement all functions in mcu.h
 *    All defines specific to ATmega48/88 reside in this file!
 *
 * Compiler: Tested with WinAVR, avr-gcc (GCC) 3.4.3
 *
 * Revision: 2.0 
 *
 *==============================================================================
 */


// The following hardware is used in the ATmega48:
// PB0 Button - active high
// PB1 Button - active high
// PB2 Button - active high (SPI chip select)
// PB3 SPI MOSI - in-system programming
// PB4 SPI MISO - in-system programming
// PB5 SPI SCK - in-system programming
// PB6 XTAL1 - see page 29 of data sheet
// PB7 XTAL2 - see page 29 of data sheet
// 
// PC0 NC
// PC1 Output to a LED - active high
// PC2 Random seed bit - connected to I2S bit clock or MCLK
// PC3 Connected to wakeup pin DD[1] of nRF24Z1
// PC4 2-wire SDA - used for both nRF24Z1 and ADC
// PC5 2-wire SCL - used for both nRF24Z1 and ADC
// PC6 Reset - in-system programming
// PC7 Doesn't exist on chip
// 
// PD0 UART RXD
// PD1 UART TXD
// PD2 INT0 - connected to IRQ of nRF24Z1
// PD3 NC
// PD4 NC
// PD5 Button - active high
// PD6 Button - active high
// PD7 Button - active high

#include "mcu.h"

// MCU specific includes, change if porting to a different MCU or compiler
#include <stdio.h>
#include <avr/interrupt.h> 
#include <avr/signal.h>
#include <avr/sleep.h> 
#include <avr/wdt.h> 
#include <avr/pgmspace.h>
#include <avr/io.h>


// Some forward declarations of functions that are not available externally
void mcu_wait_timer(void);
void mcu_wait_32ms(void);


#ifdef MCU_3686
    #define F_CPU 3686000UL                         // Oscillator on STK500
#endif
#ifdef MCU_8000
    #define F_CPU 8000000UL                         // Internal RC oscillator, no 8x division in fuse bits
#endif
#ifdef MCU_1000
    #define F_CPU 1000000UL                         // Internal RC oscillator, with 8x division in fuse bits (default for atmega48/88)
#endif


// Handler for timer/counter1 interrupt
SIGNAL(SIG_OVERFLOW1) { 
    // Simply return after interrupt
} 


// Handler for watchdog timer interrupt
SIGNAL(SIG_WATCHDOG_TIMEOUT) {
    // Simply return after interrupt. 
}


// Initialize the MCU. The atmega16 needs no other init than what is done in
// separate functions. 
void mcu_init(void) {
    DDRC = 0x0A;                                    // PC3 goes to DD[1] of nRF24Z1, PC1 goes to LED
    ACSR = 0xF0;                                    // Analog comparator is off
	
    char temp = 0b01100001;                         // Shut down Timer/Counter2, Timer/Counter0 and ADC
    temp |= 0b00000100;                             // Shut down SPI
    #ifndef DEBUG                                   // If no debug is used,
        temp |= 0b00000010;                         // shut down uart
    #endif  
    PRR = temp;                                     // Store power reduction register   
    
    mcu_wait_ms(96);                                // Wait for nRF24Z1 to load firmware and settings
}


// Halt the MCU for a number of 32ms periods using the watchdog timer, low power consumption
// Atmega48/88 goes into power down mode where only watchdog, external interrupts, and 2w address
// decode continue to run. See page 38 of full data sheet. A convenient delay time is 32ms by means 
// of watchdog interrupted sleep. 
void mcu_wait_32ms(void) {                          // Lowest power down mode makes uart very unhappy
    // Code example to change time-out value of watchdog, page 51 of full data sheet
    cli();                                          // Disable interrupts
    wdt_reset();                                    // Watchdog reset
    WDTCSR |= (1<<WDCE) | (1<<WDE);                 // Enable changes in WDTCSR
    WDTCSR = (1<<WDIE) |(1<<WDP0);                  // 4k cycles (~32ms), enable watchdog interrupts
    #ifdef DEBUG                                    // PWR_DOWN kills UART while IDLE saves it. 
        set_sleep_mode(SLEEP_MODE_IDLE);            // Low power sleep that saves UART
    #else
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);        // Lowest power sleep that kills UART, saves 0.3mA
    #endif
    sei();                                          // Enable interrutps
    sleep_mode();                                   // Wait until interrupt
    // Code example to turn off watchdog, page 50 of full data sheet
    cli();                                          // Disable interrupts
    wdt_reset();                                    // Watchdog reset
    MCUSR &= ~(1<<WDRF);                            // Set WDRF bit in MCUCR to 0 to clear watchdog interrupt flag, needed?
    WDTCSR |= (1<<WDCE) | (1<<WDE);                 // Enable changes in WDTCSR
    WDTCSR = 0x00;                                  // Turn off watchdog timer
    sei();                                          // Turn on interrupts again
}


// Halt the MCU for a number of 1ms periods by means of low-power and high-power sleeps
void mcu_wait_ms(unsigned int time) {
    extern char wakeup;

    wakeup = WAKE_WAIT;                             // Assume that the delay is going to wake up the MCU

    while ((time > 32) && (wakeup == WAKE_WAIT)) {  // Wait for set time, or until another interrupt arrives
        mcu_wait_32ms();                            // Use low-power sleep for anything above 32ms
        time -= 32;                                 // Prepare to wait some more
    }

    while ((time > 0) && (wakeup == WAKE_WAIT)) {   // Wait until set time has passed, or until another interrupt arrives
        TCNT1 = -((uint16_t)(1e-3 * F_CPU));        // Sleep 1ms. Max time at 3.686MHz is 65535 / 3686000 = 17ms
        mcu_wait_timer();                           // Do the actual sleep for 1ms
        time--;                                     // Prepare to wait a little more
    }
}


// Go in to sleep mode after the calling function has set the desired delay
// The only allowable interrupt source is timer interrupt!
void mcu_wait_timer(void) { 
    cli();                                          // Go for atomic operations while setting up the interrupt source
    TIMSK1 = (1<<TOIE1);                            // Enable t/c 1 overflow int 
    TCCR1A = 0;                                     // t/c 1 normal mode 
    TCCR1B = (1<<CS10);                             // Start timer 1 with prescaler 1 
    set_sleep_mode(SLEEP_MODE_IDLE);                // Idle mode keeps counters running
    sei();                                          // Set global interrupt flag
    sleep_mode();                                   // Wait until interrupted by pin or counter
    cli();                                          // Clear global interrupt flag
    TIMSK1 = 0x00;                                  // Disable all timer/counter interrupts
    TCCR1B = 0x00;                                  // Stop timer 1 
    sei();                                          // Turn on interrupts again
}  


// Produce a pseudo random byte by looking at a signal that is presumed to be asynchronous to the MCU clock
// Improve to flatten histogram of output!
char mcu_randombyte(void) {
//    extern char randombyte;                         // A number different from 0x00 to start the LFSR
    static char randombyte = 0xAA;
    char readbyte = 0;
    char count = 0;

    // Simulate 7-bit linear feedback shift register x^7 + x^4 + input
    
    for (count=81; count!=0; count--) {             // Number of xors to perform. Time vs. enthropy trade off
    
        if ((PINC & 0x04) != 0x00)                  // PC2 is random input from I2C bitclock, async. with MCU clock
            readbyte = 1;
        else
            readbyte = 0;
        if ((randombyte & 0x40) != 0x00)            // XORing x^7 (MSB has index 8 in LFSRs!!)
            readbyte = ~readbyte;
        if ((randombyte & 0x08) != 0x00)            // XORing x^4
            readbyte = ~readbyte;
    
        readbyte &= 0x01;                           // Only keep LSB of readbyte
        randombyte <<=1;                            // Left shift result
        randombyte |= readbyte;                     // ORing in a new LSB
    }

    return randombyte;
}


// Set up MCU's master 2-wire interface
void mcu_2w_master_init(void) {
    #ifdef MCU_3686
        TWBR = 0x0C;                                // SCL speed at 92.5kbps, not tried with ADC
    #endif
    #ifdef MCU_8000
        TWBR = 0x24;                                // SCL speed at 91kbps, works with nRF24Z1, doesn't work with ADC
    #endif
    #ifdef MCU_1000
        TWBR = 0x05;                                // Lower SCL speed suitable with low-resolution clock division, works with nRF24Z1 and ADC
    #endif

    TWSR = 0;                                       // See mega48_88 datasheet p. 215
    TWAR = 0xAA;                                    // 2-w adr. of this unit is 1010101, no answer to general call
    TWCR = (1<<TWEN);                               // Enable two-wire interface
    TWDR = 0xFF;                                    // Default content = SDA released.
}


// Read data from 2-wire slave interface of nRF24Z1, this is all MCU specific!
// DOC: Interrupts must be off during this function!
char mcu_2w_read(char devadr, char adr) {
    char failure = 0;                               // No errors have been detected this far
    char temp = 0;                                  // Temporary data container

    // Brief explanation of nRF24Z1 2-wire read:
    // Send start condition
    // Send device address with r/_w = 0
    // Send internal register address
    // Send new start condition
    // Send device address with r/_w = 1
    // Read byte, NACK when done
    // Send stop condition

    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);     // Send start condition
    loop_until_bit_is_set(TWCR,TWINT);              // Wait until the start condition has been sent
    if ((TWSR & 0xF8) != 0x08)                      // Test for valid start condition
        failure = 1;                                // Start condition failed

    if (failure==0) {
        TWDR = (devadr<<1) & 0xFE;                  // 7-bit device address, LSB=0 for write
        TWCR = (1<<TWINT) | (1<<TWEN);              // Start transmission of address
        loop_until_bit_is_set(TWCR,TWINT);          // Wait until the device address has been sent
        if ((TWSR & 0xF8) != 0x18)                  // Test for ACK after device address and _w bit
            failure = 2;                            // Device address and _w bit failed
    }

    if (failure==0) {
        TWDR = adr;                                 // Send internal address of nRF24Z1
        TWCR = (1<<TWINT) | (1<<TWEN);              // Start transmission of address
        loop_until_bit_is_set(TWCR,TWINT);          // Wait until the internal address has been sent
        if ((TWSR & 0xF8) != 0x28)                  // Test for ACK after data = internal address
            failure = 3;                            // Internal address failed
    }

    if (failure==0) {
        TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); // Send another start condition
        loop_until_bit_is_set(TWCR,TWINT);          // Wait until the start condition has been sent
        if ((TWSR & 0xF8) != 0x10)                  // Test for valid restart condition sent
            failure = 4;                            // Restart condition failed
    }
        

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -