ARM DIY进程7:I2C
有了上例的串行通讯调试终端,接下来的I2C1调试就很方便,只要一条printf()就把24C02的读写内容都显示在屏幕上了。I2C1的设置先设置GPIO引脚为开漏输出,然后初始化I2C1工作模式、主机地址、速率。初始化完成后就可以对其进行读写了。下图是读写结果通过串口发送到PC机的截屏,上次练习关于串口的初始化函数就不列出了。
图1 I2C读写结果
ARM DIY进程7:I2C
有了上例的串行通讯调试终端,接下来的I2C1调试就很方便,只要一条printf()就把24C02的读写内容都显示在屏幕上了。I2C1的设置先设置GPIO引脚为开漏输出,然后初始化I2C1工作模式、主机地址、速率。初始化完成后就可以对其进行读写了。下图是读写结果通过串口发送到PC机的截屏,上次练习关于串口的初始化函数就不列出了。
图1 I2C读写结果
相关代码:
#include "stm32f10x.h"
#include <stdio.h>
#define AT24C01A
u16 speed=2000;
u16 Count=0;
RCC_ClocksTypeDef RCC_ClockFreq;
void GPIO_Configuration(void) ;
void I2C_Configuration(void);
void Delay(u16 speed);
extern void I2C_Test(void);
extern void USART_Configuration(void);
int main(void)
{
SystemInit();
RCC_GetClocksFreq(&RCC_ClockFreq);
GPIO_Configuration();
I2C_Configuration();
USART_Configuration();
printf("写入24C02芯片128字节:\r\n");
I2C_Test();
while (1)
{
}
}
//--------
//I2C函数
//--------
#include "stm32f10x.h"
#include <stdio.h>
#define AT24C01A
#define EEPROM_ADDR 0xA0
#define I2C_PAGESIZE 4
void I2C_Configuration(void)
{
I2C_InitTypeDef I2C_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x30;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_Cmd(I2C1, ENABLE);
I2C_Init(I2C1, &I2C_InitStructure);
I2C_AcknowledgeConfig(I2C1, ENABLE);
GPIOB->ODR &=~0xff2f;
}
//-----------
//I2C_ReadS
//------------
void I2C_ReadS_24C(u8 addr ,u8* pBuffer,u16 no)
{
if(no==0)
return;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
I2C_AcknowledgeConfig(I2C1, ENABLE);
I2C_GenerateSTART(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));/*EV5,主模式*/
I2C_Send7bitAddress(I2C1, addr<<1, I2C_Direction_Receiver);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
while (no)
{
if(no==1)
{
I2C_AcknowledgeConfig(I2C1, DISABLE);
I2C_GenerateSTOP(I2C1, ENABLE);
}
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
*pBuffer = I2C_ReceiveData(I2C1);
pBuffer++;
no--;
}
I2C_AcknowledgeConfig(I2C1, ENABLE);
}
/-----------------
//I2C_Standby_24C
/------------------
void I2C_Standby_24C(void)
{
vu16 SR1_Tmp;
do
{
I2C_GenerateSTART(I2C1, ENABLE);
SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1);
I2C_Send7bitAddress(I2C1, 0, I2C_Direction_Transmitter);
}while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));
I2C_ClearFlag(I2C1, I2C_FLAG_AF);
I2C_GenerateSTOP(I2C1, ENABLE);
}
//------------------
//I2C_ByteWrite_24C
//-----------------
void I2C_ByteWrite_24C(u8 addr,u8 dat)
{
I2C_GenerateSTART(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1, addr<<1, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2C1, dat);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(I2C1, ENABLE);
I2C_Standby_24C();
}
//--------------------------
//函数名:I2C_PageWrite_24C
//--------------------------
void I2C_PageWrite_24C(u8 addr,u8* pBuffer, u8 no)
{
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
I2C_GenerateSTART(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1, addr<<1, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
while(no--)
{
I2C_SendData(I2C1, *pBuffer);
pBuffer++;
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}
I2C_GenerateSTOP(I2C1, ENABLE);
}
//--------------------
//I2C_WriteS_24C
//-------------------
void I2C_WriteS_24C(u8 addr,u8* pBuffer, u16 no)
{ u8 temp;
temp=addr % I2C_PAGESIZE;
if(temp)
{
temp=I2C_PAGESIZE-temp;
I2C_PageWrite_24C(addr,pBuffer, temp);
no-=temp;
addr+=temp;
pBuffer+=temp;
I2C_Standby_24C();
}
while(no)
{
if(no>=I2C_PAGESIZE)
{
I2C_PageWrite_24C(addr,pBuffer, I2C_PAGESIZE);
no-=I2C_PAGESIZE;
addr+=I2C_PAGESIZE;
pBuffer+=I2C_PAGESIZE;
I2C_Standby_24C();
}
else
{
I2C_PageWrite_24C(addr,pBuffer, no);
no=0;
I2C_Standby_24C();
}
}
}
void I2C_Test(void)
{
u8 i;
u8 I2c_Buf[128];
for(i=0;i<128;i++)
{
I2c_Buf[i]=i;
printf(" %x",i);
}
I2C_PageWrite_24C(4,I2c_Buf, 4);
printf("\r\n");
printf("读出24C02芯片128字节:\r\n");
for(i=0;i<128;i++)
I2c_Buf[i]=0;
I2C_Standby_24C();
I2C_ReadS_24C(0,I2c_Buf,8);
for(i=0;i<128;i++)
I2c_Buf[i]=i;
I2C_WriteS_24C(0,I2c_Buf,128);
for(i=0;i<128;i++)
I2c_Buf[i]=0;
I2C_ReadS_24C(0,I2c_Buf,128);
for(i=0;i<128;i++)
{ printf(" %x",I2c_Buf[i]);
if(I2c_Buf[i]!=i)
printf("I2C测试失败");
}
}
ARM DIY进程8:SD卡读FAT文件
读写SD卡分普通SD(SPI)和SDHC(4总线)方式,老的STM32固件库的例程只支持SPI方式,4总线方式听说只有V3.4版固件库可用,V3.5版反而用不起来了。查阅开发板硬件连接,才知道我们的DIY板还挺超前的。只支持4总线方式,无奈我的固件库现在使用的是V3.5版,也“超前”了点,看来4总线方式读写SD卡是用不起来了。不死心借来一块STM32108PKT板来熟悉一下SPI的SD卡练习。
图1 借来的STM32108PKT开发板
STM32108PKT板读SD卡SIP方式要用到连接线有:GPIOA_4-CS,GPIOA_5-CLK,GPIOA_6-MISO,GPIOA_7-MOSI。SD卡预先在PC机上创建一个子目录\ARM_DIY\,在子目录里建立一个文本文件ARM_DIY.TXT。ARM_DIY.TXT写进一些文本供显示用。
USART1连接到PC机的串口作显示终端。运行时提示插入预先建立了子目录和文件的SD卡,然后按住开发板上的“SELECT”键,在显示终端上显示ARM_DIY.TXT文件的内容。
图2 SD卡的文件总算读出来了,知其然不知其所以然也,要是老板给我一个SD卡开发项目,我的头就大了
哪位网友如果用4总线方式在ARM开发板上读写SD卡成功了,记得一起分享喔!
相关代码:
#include "STM32Lib\\stm32f10x.h"
#define GET_SELECT()(!GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7))
void TestBoard(void);
int main(void)
{
SystemInit();
RCC_GetClocksFreq(&RCC_ClockFreq);
RCC_Configuration();
USART_Configuration();
USART1_Puts("\r\n 测试SD卡,请把SD卡插入,并确保存在/ARM_DIY/ARM_DIY.txt \r\n"); /
TurnToSD();
USART1_Puts("\r\n 按下SELECT键显示SD卡ARM_DIY子目录中的ARM_DIT.TXT文件内容\r\n");
while(!GET_SELECT());
TestSD();
for(;;)
{
}
}
//------------
//SD.C
//-------------
#include "STM32Lib\\stm32f10x.h"
#include "diskio.h"
#include "tff.h"
#include "hal.h"
//#include "usart.h"
#define CMD0 (0x40+0) /* GO_IDLE_STATE */
#define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */
#define ACMD41 (0xC0+41) /* SEND_OP_COND (SDC) */
#define CMD8 (0x40+8) /* SEND_IF_COND */
#define CMD9 (0x40+9) /* SEND_CSD */
#define CMD10 (0x40+10) /* SEND_CID */
#define CMD12 (0x40+12) /* STOP_TRANSMISSION */
#define ACMD13 (0xC0+13) /* SD_STATUS (SDC) */
#define CMD16 (0x40+16) /* SET_BLOCKLEN */
#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
#define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */
#define CMD23 (0x40+23) /* SET_BLOCK_COUNT (MMC) */
#define ACMD23 (0xC0+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
#define CMD24 (0x40+24) /* WRITE_BLOCK */
#define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */
#define CMD55 (0x40+55) /* APP_CMD */
#define CMD58 (0x40+58) /* READ_OCR */
#define MMC_SELECT() GPIO_ResetBits(GPIOA, GPIO_Pin_4) /* MMC CS = L */
#define MMC_DESELECT() GPIO_SetBits(GPIOA, GPIO_Pin_4) /* MMC CS = H */
static volatile
DSTATUS Stat = STA_NOINIT;
static
BYTE CardType;
extern volatile
unsigned int Timer1, Timer2;
void SPI_Release(void);
void MMC_SPI_Config(void)
{
}
void TurnToSD(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |
RCC_APB2Periph_GPIOC |
RCC_APB2Periph_AFIO |
RCC_APB2Periph_SPI1,
ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_4);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
SPI_Cmd(SPI1, DISABLE); //必须要有才能改变MODE
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
SPI_Release();
}
#define NULL 0
void TestSD(void)
{FATFS fs;
FIL fil;
FRESULT res;
char byte[65];
u32 len;
f_mount(0,&fs);
res=f_open(&fil,"/ARM_dIY/ARM_diy.txt",FA_OPEN_EXISTING|FA_READ);
if(res!=FR_OK)
{
printf("SD卡打开文件失败\r\n");
return;
}
for(;;)
{
res = f_read(&fil, byte, sizeof(byte)-1, &len);
if (res || len == 0)
break;
byte[len]='\0';
printf(byte);
}
f_close(&fil);
f_mount(0, NULL);
}
static
u8 SPI_ReadWrite_Byte(unsigned char byte)
{
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, byte);
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
return SPI_I2S_ReceiveData(SPI1);
}
static
void SPI_LowSpeed(void)
{
SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Cmd(SPI1, ENABLE);
}
static
void SPI_HighSpeed(void)
{
SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
}
static
BYTE Wait_Ready (void)
{
BYTE res;
Timer2 = 50;
SPI_ReadWrite_Byte(0xff);;
do{
res = SPI_ReadWrite_Byte(0xff);
}while ((res != 0xFF) && Timer2);
return res;
}
static
void SPI_Release(void)
{
MMC_DESELECT();
SPI_ReadWrite_Byte(0xff);;
}
#define MMC_POWERON()
#define MMC_POWEROFF()
int chk_power(void)
{
return 1;
}
static
bool Receive_DataBlock(
BYTE *buff,
UINT btr
)
{
BYTE token;
Timer1 = 10;
do { token = SPI_ReadWrite_Byte(0xff);
} while ((token == 0xFF) && Timer1);
if(token != 0xFE) return FALSE;
do { *buff++ = SPI_ReadWrite_Byte(0xff);
} while (btr--);
SPI_ReadWrite_Byte(0xff);
SPI_ReadWrite_Byte(0xff);
return TRUE;
}
#if _READONLY == 0
static
bool Transmit_DataBlock (
const BYTE *buff,
BYTE token
)
{
BYTE resp;
UINT wc;
if (Wait_Ready() != 0xFF) return FALSE;
SPI_ReadWrite_Byte(token);
if (token != 0xFD) {
wc = 512;
do { SPI_ReadWrite_Byte(*buff++);
} while (--wc);
SPI_ReadWrite_Byte(0xFF);
SPI_ReadWrite_Byte(0xFF);
resp = SPI_ReadWrite_Byte(0xff);
if ((resp & 0x1F) != 0x05)
return FALSE;
}
return TRUE;
}
#endif
static
BYTE Send_Command(
BYTE cmd,
DWORD arg
)
{
BYTE n, res;
if (cmd & 0x80) {
cmd &= 0x7F;
res = Send_Command(CMD55, 0);
if (res > 1) return res;
}
MMC_DESELECT();
MMC_SELECT();
if (Wait_Ready() != 0xFF) return 0xFF;
SPI_ReadWrite_Byte(cmd);
SPI_ReadWrite_Byte((BYTE)(arg >> 24));
SPI_ReadWrite_Byte((BYTE)(arg >> 16));
SPI_ReadWrite_Byte((BYTE)(arg >> 8));
SPI_ReadWrite_Byte((BYTE)arg);
n = 0x01;
if (cmd == CMD0) n = 0x95;
if (cmd == CMD8) n = 0x87;
SPI_ReadWrite_Byte(n);
if (cmd == CMD12) {
SPI_ReadWrite_Byte(0xff);
}
n = 10;
do{
res = SPI_ReadWrite_Byte(0xff);
}while ((res & 0x80) && --n);
return res;
}
DSTATUS disk_initialize (
BYTE drv
)
{
BYTE n, cmd, ty, ocr[4];
if (drv) return STA_NOINIT;
if (Stat & STA_NODISK) return Stat;
MMC_SPI_Config(); //初始化IO
MMC_POWERON();
for(Timer1=50; Timer1; );
SPI_LowSpeed();
MMC_DESELECT();
Timer1 = 500;
do{
for (n = 10; n; n--) SPI_ReadWrite_Byte(0xff);
}
while((Send_Command(CMD0,0) != 1) && Timer1);
ty = 0;
Timer1 = 200;
if (Send_Command(CMD8, 0x1AA) == 1) {
for (n = 0; n < 4; n++)
ocr[n] = SPI_ReadWrite_Byte(0xff);
if (ocr[2] == 0x01 && ocr[3] == 0xAA) {
while (Timer1 && Send_Command(ACMD41, 1UL << 30));
if (Timer1 && Send_Command(CMD58, 0) == 0) {
for (n = 0; n < 4; n++)
ocr[n] = SPI_ReadWrite_Byte(0xff);
ty = (ocr[0] & 0x40) ? 12 : 4;
}
}
} else {
if (Send_Command(ACMD41, 0) <= 1) {
ty = 2; cmd = ACMD41;
} else {
ty = 1; cmd = CMD1;
}
while (Timer1 && Send_Command(cmd, 0));
if (!Timer1 || Send_Command(CMD16, 512) != 0)
ty = 0;
}
CardType = ty;
SPI_HighSpeed();
SPI_Release();
if (ty) {
Stat &= ~STA_NOINIT;
} else {
MMC_POWEROFF();
}
return Stat;
}
DSTATUS disk_status (
BYTE drv
)
{
if (drv) return STA_NOINIT;
return Stat;
}
DRESULT disk_read (
BYTE drv,
BYTE *buff,
DWORD sector,
BYTE count
)
{
if (drv || !count) return RES_PARERR;
if (Stat & STA_NOINIT) return RES_NOTRDY;
if (!(CardType & 8)) sector *= 512;
if (count == 1) {
if ((Send_Command(CMD17, sector) == 0)
&& Receive_DataBlock(buff, 512))
count = 0;
}
else {
if (Send_Command(CMD18, sector) == 0) {
do {
if (!Receive_DataBlock(buff, 512)) break;
buff += 512;
} while (--count);
Send_Command(CMD12, 0);
}
}
SPI_Release();
return count ? RES_ERROR : RES_OK;
}
#if _READONLY == 0
DRESULT disk_write (
BYTE drv,
const BYTE *buff,
DWORD sector,
BYTE count
)
{
if (drv || !count) return RES_PARERR;
if (Stat & STA_NOINIT) return RES_NOTRDY;
if (Stat & STA_PROTECT) return RES_WRPRT;
if (!(CardType & 8)) sector *= 512;
if (count == 1) {
if ((Send_Command(CMD24, sector) == 0)
&& Transmit_DataBlock(buff, 0xFE))
count = 0;
}
else { if (CardType & 6) Send_Command(ACMD23, count);
if (Send_Command(CMD25, sector) == 0) {
do {
if (!Transmit_DataBlock(buff, 0xFC)) break;
buff += 512;
} while (--count);
if (!Transmit_DataBlock(0, 0xFD))
count = 1;
}
}
SPI_Release();
return count ? RES_ERROR : RES_OK;
}
#endif
#if _USE_IOCTL != 0
DRESULT disk_ioctl (
BYTE drv,
BYTE ctrl,
void *buff
)
{
DRESULT res;
BYTE n, csd[16], *ptr = buff;
WORD csize;
if (drv) return RES_PARERR;
res = RES_ERROR;
if (ctrl == CTRL_POWER) {
switch (*ptr) {
case 0:
if (chk_power())
MMC_POWEROFF();
res = RES_OK;
break;
case 1:
MMC_POWERON();
res = RES_OK;
break;
case 2:
*(ptr+1) = (BYTE)chk_power();
res = RES_OK;
break;
default :
res = RES_PARERR;
}
}
else {
if (Stat & STA_NOINIT) return RES_NOTRDY;
switch (ctrl) {
case CTRL_SYNC :
MMC_SELECT();
if (Wait_Ready() == 0xFF)
res = RES_OK;
break;
case GET_SECTOR_COUNT :
if ((Send_Command(CMD9, 0) == 0) && Receive_DataBlock(csd, 16)) {
if ((csd[0] >> 6) == 1) {
csize = csd[9] + ((WORD)csd[8] << 8) + 1;
*(DWORD*)buff = (DWORD)csize << 10;
} else {
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
*(DWORD*)buff = (DWORD)csize << (n - 9);
}
res = RES_OK;
}
break;
case GET_SECTOR_SIZE :
*(WORD*)buff = 512;
res = RES_OK;
break;
case GET_BLOCK_SIZE :
if (CardType & 4) {
if (Send_Command(ACMD13, 0) == 0) {
SPI_ReadWrite_Byte(0xff);
if (Receive_DataBlock(csd, 16)) {
for (n = 64 - 16; n; n--) SPI_ReadWrite_Byte(0xff);
*(DWORD*)buff = 16UL << (csd[10] >> 4);
res = RES_OK;
}
}
} else {
if ((Send_Command(CMD9, 0) == 0) && Receive_DataBlock(csd, 16)) {
if (CardType & 2) {
*(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7)
+ 1) << ((csd[13] >> 6) - 1);
} else {
*(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3)
<< 3) + ((csd[11] & 224) >> 5) + 1);
}
res = RES_OK;
}
}
break;
case MMC_GET_TYPE :
*ptr = CardType;
res = RES_OK;
break;
case MMC_GET_CSD :
if (Send_Command(CMD9, 0) == 0
&& Receive_DataBlock(ptr, 16))
res = RES_OK;
break;
case MMC_GET_CID :
if (Send_Command(CMD10, 0) == 0
&& Receive_DataBlock(ptr, 16))
res = RES_OK;
break;
case MMC_GET_OCR :
if (Send_Command(CMD58, 0) == 0) {
for (n = 4; n; n--) *ptr++ = SPI_ReadWrite_Byte(0xff);
res = RES_OK;
}
break;
case MMC_GET_SDSTAT :
if (Send_Command(ACMD13, 0) == 0) {
SPI_ReadWrite_Byte(0xff);
if (Receive_DataBlock(ptr, 64))
res = RES_OK;
}
break;
default:
res = RES_PARERR;
}
}
SPI_Release();
return res;
}
#endif
DWORD get_fattime (void)
{
return 0;
}
太长了,还有一个TTF.C就不贴了。
ARM DIY进程9:正弦波信号发生器(3相50HZ)
练习利用STM32定时器1的PWM输出和定时器2的溢出中断功能,产生50HZ的3相正弦波信号。要在实验室或家中使用到三相交流电来调试嵌入式系统,有时还真是件不容易的事情。有了这个信号发生器,就方便多了。
要使用定时器,先要打开stm32f10x_conf.h中的#include "stm32x_tim.h"和#include "stm32x_misc.h",开放定时器总线.定时器1的CCR1、CCR2、CCR3通道分别对应GPIOA_PIN8-PIN11,需要将其设置为GPIO_Mode_AF_PP模式。定时器1负责PWM输出,定时器2负责在中断中查表更新各路PWM的CCRx值,得到不同的占空比。3路PWM脉冲输出经过RC滤波器(见图1)后产生相位相差120度的50HZ正弦波信号。示波器只有2踪,以B相时间轴为基准,分别拍摄了A-B和B-C的波形。
图1 外接的RC滤波器
图2 A-B 相波形
图3 B-C相波形
代码
//------
//main.c
//------
#include "STM32Lib\\stm32f10x.h"
u8 const pwm_duty[]={
0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae,
0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8,
0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5,
0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,
0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc,
0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3,
0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83,
0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51,
0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27,
0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a,
0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08,
0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23,
0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c,
0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c};
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
Tim1_Configuration();
NVIC_Configuration();
for(;;)
{
}
}
//-------
//NVIC.C
//-------
#include "STM32Lib\\stm32f10x.h"
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//-------
//GPIO.C
//-------
void GPIO_Configuration(void)
{ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //开漏输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//-------
//TIM.C
//-------
#include "STM32Lib\\stm32f10x.h"
void Tim1_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
TIM_DeInit(TIM1);
TIM_TimeBaseStructure.TIM_Prescaler = 10;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 256;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0;
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
TIM_OCInitStructure.TIM_Pulse = 1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OC1Init(TIM1,&TIM_OCInitStructure);
TIM_OC2Init(TIM1,&TIM_OCInitStructure);
TIM_OC3Init(TIM1,&TIM_OCInitStructure);
TIM1->CCR1=1;
TIM1->CCR2=33;
TIM1->CCR3=66;
TIM1->CR2 &=~0x01;
TIM_CtrlPWMOutputs(TIM1,ENABLE);
TIM_Cmd(TIM1,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_DeInit(TIM2);
TIM_TimeBaseStructure.TIM_Prescaler = 20;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 267;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV2;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2,ENABLE);
}
//-------
//中断函数
//------
void TIM2_IRQHandler(void)
{
static unsigned char i=0;
static unsigned char j=85;
static unsigned char k=170;
if (TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
TIM1->CCR1 = pwm_duty[i];
TIM1->CCR2 =pwm_duty[j];
TIM1->CCR3 = pwm_duty[k];
i++;
j++;
k++;
}
return;
}
ARM DIY进程10:CAN双机通信
觉得CAN如果玩Polling有点象陆地学游泳,还是搞个双机通信才能真正体会真实效果,但这需要2台STM32。弄来一部万利EK-STM32F,这种开发板不知道当初为何要捆绑J-LINK下载器在板上,而且其驱动程序只能兼容低版本的IAR,不支持KEIL下载,外部下载器一接上就发生冲突。花费了不少时间对其进行改造,终于能支持KLEIL下载了,并将该板的LCD显示代码从IAR环境移植到了KEIL环境,现在可以实战演练CAN了,呵呵!
CAN的接收采用中断方式,DIY开发板上的CAN连接到了PB8和PB9,需要对CAN复用功能重映射,参见图1的《用户手册》截图。
GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
双机通信中两机的通信协议设置一定要相同,而甲乙两机的ID地址要错开,本例中甲机设为TxMessage.StdId=0x12,乙机设为TxMessage.StdId=0x11 .程序运行过程按住发送键,发送方就将本机的ADC转换结果发送给对方,接收方将传送的数据显示在LCD屏幕上,并根据数值的大小分别点亮1-4只LED。连接2台机器的导线使用了双绞线,H对H,L对L。
图1
CAN双机通信连接
有奖活动 | |
---|---|
【有奖活动——B站互动赢积分】活动开启啦! | |
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |