設置 | 登錄 | 註冊

目前共有5篇帖子。

【程序】STM32單片機操作ST93C46存儲器的程序(3.2V電壓)

1樓 巨大八爪鱼 2017-2-23 19:59
#include <stm32f10x.h>

#define _BV(n) (1 << (n))
#define CS_0 (GPIOA->BRR = GPIO_BRR_BR3)
#define CS_1 (GPIOA->BSRR = GPIO_BSRR_BS3)
#define SK_0 (GPIOA->BRR = GPIO_BRR_BR5)
#define SK_1 (GPIOA->BSRR = GPIO_BSRR_BS5)
#define DI_0 (GPIOA->BRR = GPIO_BRR_BR7)
#define DI_1 (GPIOA->BSRR = GPIO_BSRR_BS7)
#define DO ((GPIOA->IDR & GPIO_IDR_IDR6) != 0)

uint16_t num = 0;
uint8_t nid = 0;
const uint8_t seg8[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};

void delay(void)
{
    uint16_t i;
    for (i = 0; i < 20000; i++);
}

void delay_short(void)
{
    uint16_t i;
    for (i = 0; i < 300; i++);
}

void ser_in(uint8_t data)
{
    uint8_t i;
    for (i = 0; i < 8; i++)
    {
        GPIOB->BRR = GPIO_BRR_BR9; // SCLK=>PB9
        if (data & 0x80)
            GPIOB->BSRR = GPIO_BSRR_BS7; // DIO=>PB7
        else
            GPIOB->BRR = GPIO_BRR_BR7;
        data <<= 1;
        GPIOB->BSRR = GPIO_BSRR_BS9;
    }
}

void par_out(void)
{
    GPIOB->BRR = GPIO_BRR_BR8; // RCLK=>PB8
    GPIOB->BSRR = GPIO_BSRR_BS8;
}

void seg_scan(void)
{
    uint8_t i;
    uint32_t n = num;
    for (i = 0; i <= 4; i++)
    {
        ser_in(seg8[n % 10]);
        ser_in(_BV(i));
        par_out();
        delay();
        n /= 10;
    }
    
    n = nid;
    for (i = 6; i <= 7; i++)
    {
        ser_in(seg8[n % 10]);
        ser_in(_BV(i));
        par_out();
        delay();
        n /= 10;
    }
}

void _93C46_WriteOP(uint8_t op)
{
    // 初態
    CS_0;
    SK_0;
    
    // 開始位
    DI_1;
    CS_1;
    delay_short(); // tCSS>=0.5us
    SK_1;
    delay_short(); // tSKH>=0.25us
    SK_0;
    //delay_short(); // tSKL>=0.25us, 由於下面已經有一句延時了, 所以這句可以不要
    
    // OP位
    if ((op & 2) == 0) // 操作碼第一位
        DI_0;
    delay_short(); // 數據在下降沿至少要保持tDIS>=0.1us
    SK_1;
    delay_short(); // 數據在上升沿至少要保持tDIH>=0.1us的時間
    SK_0;
    if (op & 1) // 改變數據, 發送操作碼第二位
        DI_1;
    else
        DI_0;
    delay_short(); // tDIS, tSKL
    
    SK_1;
    delay_short(); // tDIH, tSKH
    SK_0;
    delay_short(); // tSKL
}

void _93C46_WriteAddress(uint8_t addr)
{
    uint8_t i;
    for (i = 0; i < 6; i++)
    {
        if (addr & 0x20)
            DI_1;
        else
            DI_0;
        delay_short(); // tDIS, tSKL
        SK_1;
        delay_short(); // tSKH
        SK_0;
        addr <<= 1;
    }
    delay_short(); // tSKL
    DI_0;
}

uint16_t _93C46_ReadWord(void)
{
    uint8_t i;
    uint16_t data = 0;
    for (i = 0; i < 16; i++)
    {
        // SK上升沿出現後tPD<=0.25us,才出現本位要讀的數據
        SK_1;
        delay_short();
        data <<= 1;
        if (DO)
            data |= 1;
        SK_0;
        delay_short();
    }
    return data;
}

uint16_t _93C46_Read(uint8_t addr)
{
    uint16_t data;
    _93C46_WriteOP(2);
    _93C46_WriteAddress(addr);
    data = _93C46_ReadWord();
    CS_0;
    return data;
}

void _93C46_WriteWord(uint16_t dat)
{
    uint8_t i;
    for (i = 0; i < 16; i++)
    {
        if (dat & 0x8000)
            DI_1;
        else
            DI_0;
        delay_short(); // tDIS, tSKL
        SK_1;
        delay_short(); // tSKH
        SK_0;
        dat <<= 1;
    }
    delay_short(); // tSKL
    DI_0;
}

// 等待操作完畢
void _93C46_Wait(void)
{
    CS_0;
    CS_1;
    delay_short(); // tSV<=250ns
    while (!DO);
    CS_0;
}

// 允許/禁止擦寫
void _93C46_EnableWrite(uint8_t enabled)
{
    _93C46_WriteOP(0);
    _93C46_WriteAddress((enabled) ? 0x30 : 0x00);
    CS_0;
}

// 寫入單個存儲單元
void _93C46_Write(uint8_t addr, uint16_t dat)
{
    _93C46_WriteOP(1);
    _93C46_WriteAddress(addr);
    _93C46_WriteWord(dat);
    _93C46_Wait();
}

// 擦除單個存儲單元
void _93C46_Erase(uint8_t addr)
{
    _93C46_WriteOP(3);
    _93C46_WriteAddress(addr);
    _93C46_Wait();
}

// 擦除所有存儲單元
// 經測試,該命令可以在3.2V的電壓下完成
// 本人使用的是ST公司的93C46晶片,和STM32單片機是同一家公司生產的
void _93C46_EraseAll(void)
{
    _93C46_WriteOP(0);
    _93C46_WriteAddress(0x20);
    _93C46_Wait();
}

// 將所有的存儲單元設為指定值
// 同樣也可以在3.2V的電壓下完成
void _93C46_WriteAll(uint16_t dat)
{
    _93C46_WriteOP(0);
    _93C46_WriteAddress(0x10);
    _93C46_WriteWord(dat);
    _93C46_Wait();
}

int main(void)
{
    uint8_t i;
    
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN;
    GPIOA->CRL = 0x38303000;
    GPIOA->BSRR = GPIO_BSRR_BS6;
    GPIOB->CRH = 0x00000033;
    GPIOB->CRL = 0x30000000;
    
    /*
    _93C46_EnableWrite(1);
    for (i = 0; i < 64; i++)
        _93C46_Write(i, 40000 + i * 100 + i);
    _93C46_EnableWrite(0);
    */
    
    while (1)
    {
        num = _93C46_Read(nid);
        for (i = 0; i < 50; i++)
            seg_scan();
        
        nid++;
        if (nid > 63)
            nid = 0;
    }
}
2樓 巨大八爪鱼 2017-2-23 19:59
注意:J-Link只能提供3.2V的電壓,如果不接USB線,板上的5V輸出端只能輸出2.6V的電壓
這時只需要再插上USB線(無需拔掉J-Link),就能提供4.8V的電壓
3樓 巨大八爪鱼 2017-2-23 20:08
發送數據時,數據需要在SK=0時準備好,且保持tDIS>=0.1us的時間後才允許拉高SK。
在SK高電平期間數據還需保持tDIH>=0.1us才能釋放。
接收數據時,SK上升沿後經過tPD0=tPD1<=0.25us出現當前位的數據,因此可以在SK下降沿期間對數據進行採樣。
4樓 巨大八爪鱼 2017-2-23 20:16
等待擦寫操作完畢時,先將片選信號CS拉低,經過時間tCS>=0.25us後拉高,等待tSV<=0.25us,檢測DO的狀態。若DO=0,表明寫入還未完成。若DO=1,則操作已完畢。此時拉低CS,經過tDF<=0.1us的時間後DO變回高阻態(若單片機輸入端開了上拉電阻,則變回高電平)。

數據發送後需要經過tWP<=10ms的時間才能寫入完畢。當電源電壓為4.5~5.5V時,通常需要3ms,最短時間為0.1ms。
5樓 巨大八爪鱼 2017-2-28 16:49

回復2樓 @巨大八爪鱼 的內容:

注意:J-Link只能提供3.2V的電壓,如果不接USB線,板上的5V輸出端只能輸出2.6V的電壓
這時只需要再插上USB線(無需拔掉J-Link),就能提供4.8V的電壓
JLink裡面的跳線最好插在右邊,使JLink不向開發板供電:
http://www.openedv.com/posts/list/30861.htm

內容轉換:

回覆帖子
內容:
用戶名: 您目前是匿名發表。
驗證碼:
看不清?換一張
©2010-2025 Purasbar Ver3.0 [手機版] [桌面版]
除非另有聲明,本站採用知識共享署名-相同方式共享 3.0 Unported許可協議進行許可。