ARM DIY进程14:USB读卡器
此次练习结合USB口和SD卡,把开发板变成了名符其实的读卡器,可以在PC机上用鼠标直接操作来读写SD卡上的文件了.USB读卡器对比进程12的虚拟串口,需要支持的C文件多出了官方的usb_bot.c,usb_scsi.c,scsi_data.c,memory.c,msd.c.见图1.程序运行后windows XP系统资源里多出一个可移动磁盘,见图2.插入SD卡,就可以对SD卡进行读写操作了.我的卡只有32Mb,图3是可移动磁盘使用空间。卡内的文件夹“ARM DIY”(图4)就是上次做进程8(SD卡),预先在PC机的读卡器上建立的,那时看不到文件夹,这次可以看到全貌了。有了这个STM32的USB读卡器,从开发板上就可以直接进行FAT文件操作了.呵呵!
图1
图2



我用的SD卡存取速度较慢,在调试过程中发现初始化SD卡总是失败,经过摸索实验,发现在对SD卡初始化时加入延时等待即可解决问题,见图5.
部分代码
#include "hw_config.h"
#include "msd.h"
int main(void)
{
#ifdef DEBUG
debug();
#endif
Set_System();
Set_USBClock();
USB_Interrupts_Config();
Led_Config();
MSD_Init();
Get_Medium_Characteristics();
USB_Init();
while (1)
{
}
}
//HW_CONFIG.C
#include "stm32f10x_it.h"
#include "hw_config.h"
#include "usb_lib.h"
#include "msd.h"
u32 Mass_Memory_Size;
u32 Mass_Block_Size;
u32 Mass_Block_Count;
sMSD_CSD MSD_csd;
ErrorStatus HSEStartUpStatus;
void Set_System(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON);
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)
{ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while(RCC_GetSYSCLKSource() != 0x08)
{
}
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void Set_USBClock(void)
{
RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
}
void USB_Interrupts_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
#ifdef VECT_TAB_RAM
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN_RX0_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USB_HP_CAN_TX_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void Led_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void Led_RW_ON(void)
{
GPIO_SetBits(GPIOB, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
}
void Led_RW_OFF(void)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
}
void USB_Cable_Config (FunctionalState NewState)
{
if (NewState != DISABLE)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_8);
}
else
{
GPIO_SetBits(GPIOA, GPIO_Pin_8);
}
}
void Get_Medium_Characteristics(void)
{
u32 temp1 = 0;
u32 temp2 = 0;
MSD_GetCSDRegister(&MSD_csd);
temp1 = MSD_csd.DeviceSize + 1;
temp2 = 1 << (MSD_csd.DeviceSizeMul + 2);
Mass_Block_Count = temp1 * temp2;
Mass_Block_Size = 1 << MSD_csd.RdBlockLen;
Mass_Memory_Size = (Mass_Block_Count * Mass_Block_Size);
}
//Msd.C
#include "msd.h"
/* Select MSD Card: ChipSelect pin low */
#define MSD_CS_LOW() GPIO_ResetBits(GPIOA, GPIO_Pin_4)
#define MSD_CS_HIGH() GPIO_SetBits(GPIOA, GPIO_Pin_4)
void Delay(void)
{u8 i=0xff;
while(--i);
}

static void SPI_Config(void);
u8 MSD_Init(void)
{
u32 i = 0;
SPI_Config();
MSD_CS_HIGH();
for (i = 0; i <= 9; i++)
{ Delay(); //加入延时
MSD_WriteByte(DUMMY);
}
return (MSD_GoIdleState());
}
u8 MSD_WriteBlock(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
u32 i = 0;
u8 rvalue = MSD_RESPONSE_FAILURE;
MSD_CS_LOW();
MSD_SendCmd(MSD_WRITE_BLOCK, WriteAddr, 0xFF);
if (!MSD_GetResponse(MSD_RESPONSE_NO_ERROR))
{
MSD_WriteByte(DUMMY);
MSD_WriteByte(0xFE);
for (i = 0; i < NumByteToWrite; i++)
{
/* Send the pointed byte */
MSD_WriteByte(*pBuffer);
pBuffer++;
}
MSD_ReadByte();
MSD_ReadByte();
if (MSD_GetDataResponse() == MSD_DATA_OK)
rvalue = MSD_RESPONSE_NO_ERROR;
}
MSD_CS_HIGH();
MSD_WriteByte(DUMMY);
return rvalue;
}
u8 MSD_ReadBlock(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
{
u32 i = 0;
u8 rvalue = MSD_RESPONSE_FAILURE;
MSD_CS_LOW();
MSD_SendCmd(MSD_READ_SINGLE_BLOCK, ReadAddr, 0xFF);
if (!MSD_GetResponse(MSD_RESPONSE_NO_ERROR))
{
if (!MSD_GetResponse(MSD_START_DATA_SINGLE_BLOCK_READ))
{
for (i = 0; i < NumByteToRead; i++)
{
*pBuffer = MSD_ReadByte();
pBuffer++;
}
MSD_ReadByte();
MSD_ReadByte();
rvalue = MSD_RESPONSE_NO_ERROR;
}
}
MSD_CS_HIGH();
MSD_WriteByte(DUMMY);
return rvalue;
}
u8 MSD_WriteBuffer(u8* pBuffer, u32 WriteAddr, u32 NumByteToWrite)
{
u32 i = 0, NbrOfBlock = 0, Offset = 0;
u8 rvalue = MSD_RESPONSE_FAILURE;
NbrOfBlock = NumByteToWrite / BLOCK_SIZE;
MSD_CS_LOW();
while (NbrOfBlock --)
{
MSD_SendCmd(MSD_WRITE_BLOCK, WriteAddr + Offset, 0xFF);
if (MSD_GetResponse(MSD_RESPONSE_NO_ERROR))
{
return MSD_RESPONSE_FAILURE;
}
MSD_WriteByte(DUMMY);
MSD_WriteByte(MSD_START_DATA_SINGLE_BLOCK_WRITE);
for (i = 0; i < BLOCK_SIZE; i++)
{
MSD_WriteByte(*pBuffer);
pBuffer++;
}
Offset += 512;
MSD_ReadByte();
MSD_ReadByte();
if (MSD_GetDataResponse() == MSD_DATA_OK)
rvalue = MSD_RESPONSE_NO_ERROR;
else
rvalue = MSD_RESPONSE_FAILURE;
}
MSD_CS_HIGH();
MSD_WriteByte(DUMMY);
return rvalue;
}
u8 MSD_ReadBuffer(u8* pBuffer, u32 ReadAddr, u32 NumByteToRead)
{
u32 i = 0, NbrOfBlock = 0, Offset = 0;
u8 rvalue = MSD_RESPONSE_FAILURE;
NbrOfBlock = NumByteToRead / BLOCK_SIZE;
MSD_CS_LOW();
while (NbrOfBlock --)
{
MSD_SendCmd (MSD_READ_SINGLE_BLOCK, ReadAddr + Offset, 0xFF);
if (MSD_GetResponse(MSD_RESPONSE_NO_ERROR))
{
return MSD_RESPONSE_FAILURE;
}
if (!MSD_GetResponse(MSD_START_DATA_SINGLE_BLOCK_READ))
{
for (i = 0; i < BLOCK_SIZE; i++)
{
*pBuffer = MSD_ReadByte();
pBuffer++;
}
Offset += 512;
MSD_ReadByte();
MSD_ReadByte();
rvalue = MSD_RESPONSE_NO_ERROR;
}
else
rvalue = MSD_RESPONSE_FAILURE;
}
MSD_CS_HIGH();
MSD_WriteByte(DUMMY);
return rvalue;
}
u8 MSD_GetCSDRegister(sMSD_CSD* MSD_csd)
{
u32 i = 0;
u8 rvalue = MSD_RESPONSE_FAILURE;
u8 CSD_Tab[16];
MSD_CS_LOW();
MSD_SendCmd(MSD_SEND_CSD, 0, 0xFF);
if (!MSD_GetResponse(MSD_RESPONSE_NO_ERROR))
{
if (!MSD_GetResponse(MSD_START_DATA_SINGLE_BLOCK_READ))
{
for (i = 0; i < 16; i++)
{
CSD_Tab[i] = MSD_ReadByte();
}
}
MSD_WriteByte(DUMMY);
MSD_WriteByte(DUMMY);
rvalue = MSD_RESPONSE_NO_ERROR;
}
MSD_CS_HIGH();
MSD_WriteByte(DUMMY);
MSD_csd->CSDStruct = (CSD_Tab[0] & 0xC0) >> 6;
MSD_csd->SysSpecVersion = (CSD_Tab[0] & 0x3C) >> 2;
MSD_csd->Reserved1 = CSD_Tab[0] & 0x03;
MSD_csd->TAAC = CSD_Tab[1] ;
MSD_csd->NSAC = CSD_Tab[2];
MSD_csd->MaxBusClkFrec = CSD_Tab[3];
MSD_csd->CardComdClasses = CSD_Tab[4] << 4;
MSD_csd->CardComdClasses |= (CSD_Tab[5] & 0xF0) >> 4;
MSD_csd->RdBlockLen = CSD_Tab[5] & 0x0F;
MSD_csd->PartBlockRead = (CSD_Tab[6] & 0x80) >> 7;
MSD_csd->WrBlockMisalign = (CSD_Tab[6] & 0x40) >> 6;
MSD_csd->RdBlockMisalign = (CSD_Tab[6] & 0x20) >> 5;
MSD_csd->DSRImpl = (CSD_Tab[6] & 0x10) >> 4;
MSD_csd->Reserved2 = 0; /* Reserved */
MSD_csd->DeviceSize = (CSD_Tab[6] & 0x03) << 10;
MSD_csd->DeviceSize |= (CSD_Tab[7]) << 2;
MSD_csd->DeviceSize |= (CSD_Tab[8] & 0xC0) >> 6;
MSD_csd->MaxRdCurrentVDDMin = (CSD_Tab[8] & 0x38) >> 3;
MSD_csd->MaxRdCurrentVDDMax = (CSD_Tab[8] & 0x07);
MSD_csd->MaxWrCurrentVDDMin = (CSD_Tab[9] & 0xE0) >> 5;
MSD_csd->MaxWrCurrentVDDMax = (CSD_Tab[9] & 0x1C) >> 2;
MSD_csd->DeviceSizeMul = (CSD_Tab[9] & 0x03) << 1;
MSD_csd->DeviceSizeMul |= (CSD_Tab[10] & 0x80) >> 7;
MSD_csd->EraseGrSize = (CSD_Tab[10] & 0x7C) >> 2;
MSD_csd->EraseGrMul = (CSD_Tab[10] & 0x03) << 3;
MSD_csd->EraseGrMul |= (CSD_Tab[11] & 0xE0) >> 5;
MSD_csd->WrProtectGrSize = (CSD_Tab[11] & 0x1F);
MSD_csd->WrProtectGrEnable = (CSD_Tab[12] & 0x80) >> 7;
MSD_csd->ManDeflECC = (CSD_Tab[12] & 0x60) >> 5;
MSD_csd->WrSpeedFact = (CSD_Tab[12] & 0x1C) >> 2;
MSD_csd->MaxWrBlockLen = (CSD_Tab[12] & 0x03) << 2;
MSD_csd->MaxWrBlockLen |= (CSD_Tab[13] & 0xc0) >> 6;
MSD_csd->WriteBlockPaPartial = (CSD_Tab[13] & 0x20) >> 5;
MSD_csd->Reserved3 = 0;
MSD_csd->ContentProtectAppli = (CSD_Tab[13] & 0x01);
MSD_csd->FileFormatGrouop = (CSD_Tab[14] & 0x80) >> 7;
MSD_csd->CopyFlag = (CSD_Tab[14] & 0x40) >> 6;
MSD_csd->PermWrProtect = (CSD_Tab[14] & 0x20) >> 5;
MSD_csd->TempWrProtect = (CSD_Tab[14] & 0x10) >> 4;
MSD_csd->FileFormat = (CSD_Tab[14] & 0x0C) >> 2;
MSD_csd->ECC = (CSD_Tab[14] & 0x03);
MSD_csd->CRC = (CSD_Tab[15] & 0xFE) >> 1;
MSD_csd->Reserved4 = 1;
return rvalue;
}
u8 MSD_GetCIDRegister(sMSD_CID* MSD_cid)
{
u32 i = 0;
u8 rvalue = MSD_RESPONSE_FAILURE;
u8 CID_Tab[16];
MSD_CS_LOW();
MSD_SendCmd(MSD_SEND_CID, 0, 0xFF);
if (!MSD_GetResponse(MSD_RESPONSE_NO_ERROR))
{
if (!MSD_GetResponse(MSD_START_DATA_SINGLE_BLOCK_READ))
{
for (i = 0; i < 16; i++)
{
CID_Tab[i] = MSD_ReadByte();
}
}
MSD_WriteByte(DUMMY);
MSD_WriteByte(DUMMY);
rvalue = MSD_RESPONSE_NO_ERROR;
}
MSD_CS_HIGH();
MSD_WriteByte(DUMMY);
MSD_cid->ManufacturerID = CID_Tab[0];
MSD_cid->OEM_AppliID = CID_Tab[1] << 8;
MSD_cid->OEM_AppliID |= CID_Tab[2];
MSD_cid->ProdName1 = CID_Tab[3] << 24;
MSD_cid->ProdName1 |= CID_Tab[4] << 16;
MSD_cid->ProdName1 |= CID_Tab[5] << 8;
MSD_cid->ProdName1 |= CID_Tab[6];
MSD_cid->ProdName2 = CID_Tab[7];
MSD_cid->ProdRev = CID_Tab[8];
MSD_cid->ProdSN = CID_Tab[9] << 24;
MSD_cid->ProdSN |= CID_Tab[10] << 16;
MSD_cid->ProdSN |= CID_Tab[11] << 8;
MSD_cid->ProdSN |= CID_Tab[12];
MSD_cid->Reserved1 |= (CID_Tab[13] & 0xF0) >> 4;
MSD_cid->ManufactDate = (CID_Tab[13] & 0x0F) << 8;
MSD_cid->ManufactDate |= CID_Tab[14];
MSD_cid->CRC = (CID_Tab[15] & 0xFE) >> 1;
MSD_cid->Reserved2 = 1;
return rvalue;
}
void MSD_SendCmd(u8 Cmd, u32 Arg, u8 Crc)
{
u32 i = 0x00;
u8 Frame[6];
Frame[0] = (Cmd | 0x40);
Frame[1] = (u8)(Arg >> 24);
Frame[2] = (u8)(Arg >> 16);
Frame[3] = (u8)(Arg >> 8);
Frame[4] = (u8)(Arg);
Frame[5] = (Crc);
for (i = 0; i < 6; i++)
MSD_WriteByte(Frame[i]);
}
u8 MSD_GetDataResponse(void)
{
u32 i = 0;
u8 response, rvalue;
while (i <= 64)
{
response = MSD_ReadByte();
response &= 0x1F;
switch (response)
{
case MSD_DATA_OK:
{
rvalue = MSD_DATA_OK;
break;
}
case MSD_DATA_CRC_ERROR:
return MSD_DATA_CRC_ERROR;
case MSD_DATA_WRITE_ERROR:
return MSD_DATA_WRITE_ERROR;
default:
{
rvalue = MSD_DATA_OTHER_ERROR;
break;
}
}
if (rvalue == MSD_DATA_OK)
break;
i++;
}
while (MSD_ReadByte() == 0);
return response;
}
u8 MSD_GetResponse(u8 Response)
{
u32 Count = 0xFFF;
while ((MSD_ReadByte() != Response) && Count)
Count--;
if (Count == 0)
return MSD_RESPONSE_FAILURE;
else
return MSD_RESPONSE_NO_ERROR;
}
u16 MSD_GetStatus(void)
{
u16 Status = 0;
MSD_CS_LOW();
MSD_SendCmd(MSD_SEND_STATUS, 0, 0xFF);
Status = MSD_ReadByte();
Status |= (u16)(MSD_ReadByte() << 8);
MSD_CS_HIGH();
MSD_WriteByte(DUMMY);
return Status;
}
u8 MSD_GoIdleState(void)
{
MSD_CS_LOW();
MSD_SendCmd(MSD_GO_IDLE_STATE, 0, 0x95);
if (MSD_GetResponse(MSD_IN_IDLE_STATE))
{
return MSD_RESPONSE_FAILURE;
}
do
{
MSD_CS_HIGH();
Delay();
MSD_WriteByte(DUMMY);
Delay();
MSD_CS_LOW();
Delay(); //加入延时
MSD_SendCmd(MSD_SEND_OP_COND, 0, 0xFF);
}
while (MSD_GetResponse(MSD_RESPONSE_NO_ERROR));
MSD_CS_HIGH();
MSD_WriteByte(DUMMY);
return MSD_RESPONSE_NO_ERROR;
}
void MSD_WriteByte(u8 Data)
{
while (SPI_GetFlagStatus(SPI1, SPI_FLAG_TXE) == RESET);
SPI_SendData(SPI1, Data);
}
u8 MSD_ReadByte(void)
{
u8 Data = 0;
while (SPI_GetFlagStatus(SPI1, SPI_FLAG_TXE) == RESET);
SPI_SendData(SPI1, DUMMY);
while (SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE) == RESET);
Data = SPI_ReceiveData(SPI1);
return Data;
}
void SPI_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, 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_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
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_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);
}

ARM DIY进程15:uCOS-II移植
要真正理解和掌握uCOS-II移植,并非易事。这里的uCOS-II的移植练习其实只是拷贝大王加补丁。移植中建立了4个任务:Task1_LED1-Task1_LED4,它们以不同的TS_TICKS_PER_SEC延时时长,点亮和熄灭LED1-LED4。我在移植中把原来的3.3V的I/O驱动5V的LCD代码加入,在每个任务执行中在屏幕上显示各个任务中LED的工作状态,并与开发板上的4只LED状态相对应,1代表亮,0代表灭。其实移植工作比较简 单,主要代码都是人家写好的,我们只是把自己的代码融合进去而已,体验体验uCOS-II移植实际效果。


部分代码
void main(void)
{
#if (OS_TASK_NAME_SIZE > 14) && (OS_TASK_STAT_EN > 0)
INT8U err;
#endif
OSInit();
LcdInit();
TestLCDS();
//设置空闲任务名称
#if OS_TASK_NAME_SIZE > 14
OSTaskNameSet(OS_TASK_IDLE_PRIO, "uC/OS-II Idle", &err);
#endif
//设置统计任务名称
#if (OS_TASK_NAME_SIZE > 14) && (OS_TASK_STAT_EN > 0)
OSTaskNameSet(OS_TASK_STAT_PRIO, "uC/OS-II Stat", &err);
#endif
//用任务建立任务
OSTaskCreateExt(APP_TaskStart, //void (*task)(void *pd) 任务首地址
(void *)0, //void *pdata 数据指针
&APP_TaskStartStk[APP_TASK_START_STK_SIZE - 1], //OS_STK *ptos 指向任务堆栈栈顶的指针
(INT8U)APP_TASK_START_PRIO, //INT8U prio 任务优先级
(INT16U)APP_TASK_START_ID, //INT16U id 任务的ID号
&APP_TaskStartStk[0], //OS_STK *pbos 指向任务堆栈栈底的指针
(INT32U)APP_TASK_START_STK_SIZE, //INT32U stk_size 堆栈容量
(void *)0, //void *pnext 数据指针
OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); //INT16U opt 设定OSTaskCreateExt的选项
#if OS_TASK_NAME_SIZE > 14
OSTaskNameSet(APP_TASK_START_PRIO, "Task-Start", &err);
#endif
OSStart();
}
static void Task1_LED1(void *pdata)
{
pdata = pdata;
while(1)
{
GPIO_ResetBits(GPIOE, GPIO_Pin_5);
byte_disp(7,3,'1'); //补丁
OSTimeDly(OS_TICKS_PER_SEC * 2);
GPIO_SetBits(GPIOE, GPIO_Pin_5);
byte_disp(7,3,'0'); //补丁
OSTimeDly(OS_TICKS_PER_SEC * 2);
}
}
static void Task2_LED2(void *pdata)
{
pdata = pdata;
while(1)
{
GPIO_ResetBits(GPIOE, GPIO_Pin_4);
byte_disp(7,7,'1'); //补丁
OSTimeDly(OS_TICKS_PER_SEC / 1);
GPIO_SetBits(GPIOE, GPIO_Pin_4);
byte_disp(7,7,'0'); //补丁
OSTimeDly(OS_TICKS_PER_SEC / 1);
}
}
static void Task3_LED3(void *pdata)
{
pdata = pdata;
while(1)
{
GPIO_ResetBits(GPIOE, GPIO_Pin_3);
byte_disp(7,11,'1'); //补丁
OSTimeDly(OS_TICKS_PER_SEC / 2);
GPIO_SetBits(GPIOE, GPIO_Pin_3);
byte_disp(7,11,'0'); //补丁
OSTimeDly(OS_TICKS_PER_SEC / 2);
}
}
static void Task4_LED4(void *pdata)
{
pdata = pdata;
while(1)
{
GPIO_ResetBits(GPIOE, GPIO_Pin_2);
byte_disp(7,15,'1'); //补丁
OSTimeDly(OS_TICKS_PER_SEC / 4);
GPIO_SetBits(GPIOE, GPIO_Pin_2);
byte_disp(7,15,'0'); //补丁
OSTimeDly(OS_TICKS_PER_SEC / 4);
}
}
//bsp.c(补丁部分)
static void BSP_LED_Init (void)
{
GPIO_InitTypeDef gpio_init;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
gpio_init.GPIO_Pin = BSP_GPIOE_LED1 | BSP_GPIOE_LED2 | BSP_GPIOE_LED3 | BSP_GPIOE_LED4;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOE, &gpio_init);
}
/*
*********************************************************************************************************
* BSP_LED_On()
*
* Description : Turn ON any or all the LEDs on the board.
*
* Argument(s) : led The ID of the LED to control:
*
* 0 turn ON all LEDs on the board
* 1 turn ON LED 1
* 2 turn ON LED 2
* 3 turn ON LED 3
* 4 turn ON LED 4
*
* Return(s) : none.
*
* Caller(s) : Application.
*
* Note(s) : none.
*********************************************************************************************************
*/
void BSP_LED_On (CPU_INT08U led)
{
switch (led) {
case 0:
GPIO_SetBits(GPIOE, BSP_GPIOE_LED1 | BSP_GPIOE_LED2 | BSP_GPIOE_LED3 | BSP_GPIOE_LED4);
break;
case 1:
GPIO_SetBits(GPIOE, BSP_GPIOE_LED1);
break;
case 2:
GPIO_SetBits(GPIOE, BSP_GPIOE_LED2);
break;
case 3:
GPIO_SetBits(GPIOE, BSP_GPIOE_LED3);
break;
case 4:
GPIO_SetBits(GPIOE, BSP_GPIOE_LED4);
break;
default:
break;
}
}
/*
*********************************************************************************************************
* BSP_LED_Off()
*
* Description : Turn OFF any or all the LEDs on the board.
*
* Argument(s) : led The ID of the LED to control:
*
* 0 turn OFF all LEDs on the board
* 1 turn OFF LED 1
* 2 turn OFF LED 2
* 3 turn OFF LED 3
* 4 turn OFF LED 4
*
* Return(s) : none.
*
* Caller(s) : Application.
*
* Note(s) : none.
*********************************************************************************************************
*/
void BSP_LED_Off (CPU_INT08U led)
{
switch (led) {
case 0:
GPIO_ResetBits(GPIOE, BSP_GPIOE_LED1 | BSP_GPIOE_LED2 | BSP_GPIOE_LED3 | BSP_GPIOE_LED4);
break;
case 1:
GPIO_ResetBits(GPIOE, BSP_GPIOE_LED1);
break;
case 2:
GPIO_ResetBits(GPIOE, BSP_GPIOE_LED2);
break;
case 3:
GPIO_ResetBits(GPIOE, BSP_GPIOE_LED3);
break;
case 4:
GPIO_ResetBits(GPIOE, BSP_GPIOE_LED4);
break;
default:
break;
}
}
/*
*********************************************************************************************************
* BSP_LED_Toggle()
*
* Description : TOGGLE any or all the LEDs on the board.
*
* Argument(s) : led The ID of the LED to control:
*
* 0 TOGGLE all LEDs on the board
* 1 TOGGLE LED 1
* 2 TOGGLE LED 2
* 3 TOGGLE LED 3
* 4 TOGGLE LED 4
*
* Return(s) : none.
*
* Caller(s) : Application.
*
* Note(s) : none.
*********************************************************************************************************
*/
void BSP_LED_Toggle (CPU_INT08U led)
{
CPU_INT32U pins;
pins = GPIO_ReadOutputData(GPIOE);
switch (led) {
case 0:
BSP_LED_Toggle(1);
BSP_LED_Toggle(2);
BSP_LED_Toggle(3);
BSP_LED_Toggle(4);
break;
case 1:
if ((pins & BSP_GPIOE_LED1) == 0) {
GPIO_SetBits( GPIOE, BSP_GPIOE_LED1);
} else {
GPIO_ResetBits(GPIOE, BSP_GPIOE_LED1);
}
break;
case 2:
if ((pins & BSP_GPIOE_LED2) == 0) {
GPIO_SetBits( GPIOE, BSP_GPIOE_LED2);
} else {
GPIO_ResetBits(GPIOE, BSP_GPIOE_LED2);
}
break;
case 3:
if ((pins & BSP_GPIOE_LED3) == 0) {
GPIO_SetBits( GPIOE, BSP_GPIOE_LED3);
} else {
GPIO_ResetBits(GPIOE, BSP_GPIOE_LED3);
}
break;
case 4:
if ((pins & BSP_GPIOE_LED4) == 0) {
GPIO_SetBits( GPIOE, BSP_GPIOE_LED4);
} else {
GPIO_ResetBits(GPIOE, BSP_GPIOE_LED4);
}
break;
default:
break;
}
}
}
文件结构


ARM DIY进程16: 以太网
在淘宝网上淘到1片ENC28J60模块19.8元,包括运费不到32元(图1),做工确实还不错,还赠送调试软件和资料,挺实惠的。终于可以玩玩STM32以太网了。查阅开发板上以太网模块接口竟然与淘到的ENC28J60模块接口完全一致(图2)。用1条10芯电缆线两头一插就OK了。
用1条RJ45网线连接ENC28J60模块到路由器上,注意这是要用直连方式,如果是直接连到PC机网卡上,就要用交叉线了。PC机上IP地址我设在192.168.1.200,ENC28J60模块设在192.168.1.45,IP地址前面3组要相同,最后的一组要错开。
图1
图2
程序运行后,在PC机上先执行“开始-运行-CMD",输入PING 192.168.1.45,出现图3画面,可以知道开发板已经和以太网已经连接上了。接着在PC机的浏览窗口输入"HTTP://192.168.1.45/888/"(888是我在程序中设定登录密码),远程登录成功后,出现图4画面,这时,用鼠标点击屏幕中间的“开启LED”,即可点亮开发板上的4只LED,随后点击“关闭LED”图5,可关闭开发板上的4只LED。这次总算亲自体验一下STM32以太网远程控制的过程了。
图3
图4
图5

大部分代码都是别人写好的。驱动ENC28J60要用到SPI功能,开发板上硬件连接是用到SPI2,要修改的主要有几处:
//SPI.C
void SPI2_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOG|RCC_APB2Periph_GPIOE, ENABLE);
/* SPI2 Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
GPIO_SetBits(GPIOB, GPIO_Pin_12); //PB12 CS
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB, GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5; //LED
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_SetBits(GPIOG, GPIO_Pin_7) ; //PG7 RST
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOG, &GPIO_InitStructure);
/* Configure SPI2 pins: NSS, SCK, MISO and MOSI */ //SPI2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* SPI2 configuration */
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_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
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(SPI2, &SPI_InitStructure);
/* Enable SPI2 */
SPI_Cmd(SPI2, ENABLE);
}
//SPI2读写一字节数据
unsigned char SPI2_ReadWrite(unsigned char writedat)
{
/* Loop while DR register in not emplty */
while (SPI_GetFlagStatus(SPI2, SPI_FLAG_TXE) == RESET);
/* Send byte through the SPI1 peripheral */
SPI_SendData(SPI2, writedat);
/* Wait to receive a byte */
while (SPI_GetFlagStatus(SPI2, SPI_FLAG_RXNE) == RESET);
/* Return the byte read from the SPI bus */
return SPI_ReceiveData(SPI2);
}
//simple_server.c
#define PSTR(s) s
static u8 mymac[6] =
{
0x54, 0x55, 0x58, 0x10, 0x00, 0x24
};
static u8 myip[4] ={ 192, 168, 1, 45};
static char baseurl[] = "http://192.168.1.45/"; //IP地址在这里修改
static u16 mywwwport = 80;
static u16 myudpport = 1200;
#define BUFFER_SIZE 1500
static u8 buf[BUFFER_SIZE + 1];
static char password[] = "888"; //密码在这里修改
u8 verify_password(char* str)
{
if (strncmp(password, str, sizeof(password)-1) == 0)
{
return(1);
}
return(0);
}
u8 analyse_get_url(char* str)
{
u8 i = 0;
if (verify_password(str) == 0)
{
return((u8)-1);
}
while (*str && i<10 && *str>',' && *str < '{')
{
if (*str == '/')
{
str++;
break;
}
i++;
str++;
}
if (*str <0x3a && *str> 0x2f)
{
return(*str - 0x30);
}
return((u8)-2);
}
u16 print_webpage(u8* buf, u8 on_off)
{
u16 plen; //网页内容在这里修改
plen = fill_tcp_data_p(buf, 0, PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nPragma: no-cache\r\n\r\n"));
plen = fill_tcp_data_p(buf, plen, PSTR(" <center><p>欢迎来到EEPW电子产品世界以太网远程控制中心</a><p>"));
plen = fill_tcp_data_p(buf, plen, PSTR("<center><p>开发板上LED1-LED4 当前状态: "));
if (on_off)
{
plen = fill_tcp_data_p(buf, plen, PSTR("<font color=\"#FF0000\"> 亮</font>"));
}
else
{
plen = fill_tcp_data_p(buf, plen, PSTR("灭"));
}
plen = fill_tcp_data_p(buf, plen, PSTR(" <small><a href=\""));
plen = fill_tcp_data(buf, plen, baseurl);
plen = fill_tcp_data(buf, plen, password);
plen = fill_tcp_data_p(buf, plen, PSTR("\">[刷新]</a></small></p>\n<p><a href=\""));
// the url looks like this http://baseurl/password/command
plen = fill_tcp_data(buf, plen, baseurl);
plen = fill_tcp_data(buf, plen, password);
if (on_off)
{
plen = fill_tcp_data_p(buf, plen, PSTR("/0\">关闭LED</a><p>"));
}
else
{
plen = fill_tcp_data_p(buf, plen, PSTR("/1\">开启LED</a><p>"));
}
plen = fill_tcp_data_p(buf, plen, PSTR("STM32 ARM DIY 开发板 LED 远程控制试验</a><p>"));
plen = fill_tcp_data_p(buf, plen, PSTR("</a><p>"));
plen = fill_tcp_data_p(buf, plen, PSTR("--Wenyangzeng DIY 进程 16--</a><p>"));
return(plen);
}
int simple_server(void)
{
u16 plen;
u16 dat_p;
u8 i = 0;
u8 cmd_pos = 0;
u8 cmd;
u8 payloadlen = 0;
char str[30];
char cmdval;
enc28j60Init(mymac);
str[0]=(char)enc28j60getrev();
init_ip_arp_udp_tcp(mymac, myip, mywwwport);
enc28j60PhyWrite(PHLCON, 0x476);
enc28j60clkout(2); // change clkout from 6.25MHz to 12.5MHz
while (1)
{
plen = enc28j60PacketReceive(BUFFER_SIZE, buf);
if (plen == 0)
{
continue;
}
if (eth_type_is_arp_and_my_ip(buf, plen))
{
make_arp_answer_from_request(buf);
continue;
}
if (eth_type_is_ip_and_my_ip(buf, plen) == 0)
{
continue;
}
if (buf[IP_PROTO_P] == IP_PROTO_ICMP_V &&
buf[ICMP_TYPE_P] == ICMP_TYPE_ECHOREQUEST_V)
{
make_echo_reply_from_request(buf, plen);
continue;
}
if (buf[IP_PROTO_P] == IP_PROTO_TCP_V &&
buf[TCP_DST_PORT_H_P] == 0 &&
buf[TCP_DST_PORT_L_P] == mywwwport)
{
if (buf[TCP_FLAGS_P] & TCP_FLAGS_SYN_V)
{
make_tcp_synack_from_syn(buf);
continue;
}
if (buf[TCP_FLAGS_P] & TCP_FLAGS_ACK_V)
{
init_len_info(buf); // init some data structures
dat_p = get_tcp_data_pointer();
if (dat_p == 0)
{
if (buf[TCP_FLAGS_P] & TCP_FLAGS_FIN_V)
{
make_tcp_ack_from_any(buf);
}
continue;
}
if (strncmp("GET ", (char *) &(buf[dat_p]), 4) != 0)
{
plen = fill_tcp_data_p(buf, 0, PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<h1>200 OK</h1>"));
goto SENDTCP;
}
if (strncmp("/ ", (char *) &(buf[dat_p + 4]), 2) == 0)
{
plen = fill_tcp_data_p(buf, 0, PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"));
plen = fill_tcp_data_p(buf, plen, PSTR("<p>Usage: "));
plen = fill_tcp_data(buf, plen, baseurl);
plen = fill_tcp_data_p(buf, plen, PSTR("password</p>"));
goto SENDTCP;
}
cmd = analyse_get_url((char *) &(buf[dat_p + 5]));
if (cmd ==(u8)-1)
{
plen = fill_tcp_data_p(buf, 0, PSTR("HTTP/1.0 401 Unauthorized\r\nContent-Type: text/html\r\n\r\n<h1>401 Unauthorized</h1>"));
goto SENDTCP;
}
if (cmd == 1)
{ / /LED控制在这里修改
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
GPIO_ResetBits(GPIOE,GPIO_Pin_4);
GPIO_ResetBits(GPIOE,GPIO_Pin_3);
GPIO_ResetBits(GPIOE,GPIO_Pin_2);
i = 1;
} else
if (cmd == 0)
{
GPIO_SetBits(GPIOE,GPIO_Pin_5);
GPIO_SetBits(GPIOE,GPIO_Pin_4);
GPIO_SetBits(GPIOE,GPIO_Pin_3);
GPIO_SetBits(GPIOE,GPIO_Pin_2);
i = 0;
}
plen = print_webpage(buf, (i));
SENDTCP :
make_tcp_ack_from_any(buf);
make_tcp_ack_with_data(buf, plen);
continue;
}
}
if (buf[IP_PROTO_P] == IP_PROTO_UDP_V &&
buf[UDP_DST_PORT_H_P] == 4 &&
buf[UDP_DST_PORT_L_P] == 0xb0)
{
payloadlen = buf[UDP_LEN_L_P] - UDP_HEADER_LEN;
if (verify_password((char *) &(buf[UDP_DATA_P])))
{
cmd_pos = 0;
while (cmd_pos < payloadlen)
{
cmd_pos++;
if (buf[UDP_DATA_P + cmd_pos] == ',')
{
cmd_pos++;
break;
}
}
if (cmd_pos<2 ||
cmd_pos>payloadlen - 3 ||
buf[UDP_DATA_P + cmd_pos + 1] != '=')
{
strcpy(str, "e=no_cmd");
goto ANSWER;
}
if (buf[UDP_DATA_P + cmd_pos] == 't')
{
cmdval = buf[UDP_DATA_P + cmd_pos + 2];
if (cmdval == '1')
{
strcpy(str, "t=1");
goto ANSWER;
}
else if (cmdval == '0')
{
strcpy(str, "t=0");
goto ANSWER;
}
else if (cmdval == '?')
{
strcpy(str, "t=0");
goto ANSWER;
}
}
strcpy(str, "e=no_such_cmd");
goto ANSWER;
}
strcpy(str, "e=invalid_pw");
ANSWER : make_udp_reply_from_request(buf, str, strlen(str), myudpport);
}
}
}