#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;
}
}