【程序】STM32单片机操作ST93C46存储器的程序(3.2V电压)

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


注意:J-Link只能提供3.2V的电压,如果不接USB线,板上的5V输出端只能输出2.6V的电压
这时只需要再插上USB线(无需拔掉J-Link),就能提供4.8V的电压

发送数据时,数据需要在SK=0时准备好,且保持tDIS>=0.1us的时间后才允许拉高SK。
在SK高电平期间数据还需保持tDIH>=0.1us才能释放。
接收数据时,SK上升沿后经过tPD0=tPD1<=0.25us出现当前位的数据,因此可以在SK下降沿期间对数据进行采样。

等待擦写操作完毕时,先将片选信号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。

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

巨大八爪鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值