ARM DIY进程5:RTC
曾经玩过HT1380实时时钟,觉得玩STM32的这个RTC应该也没有什么大不了的。岂料真的进入了。才知道并非易事。STM32的RTC只是个简单的秒中断定时器,它的年月日时分秒要存储在备份寄存器中。使用时要开放stm32f10x_bkp.h、stm32f10x_pwr.h和stm32f10x_rtc.h。还要使能内部的RCC_APB1Periph_PWR 和RCC_APB1Periph_BKP,还要开放RTC中断。年月日时分秒,闰年等等都要自己计算。晕!
如果你想要在DIY开放板上COPY范例代码来直接套用,由于硬件方面牵涉到LCD显示电路引脚的不同和显示代码的差异,真的不像运行跑马灯那样简单了。费了九牛二虎之力,总算让RTC时钟跑起来了。图1中显示结果是相隔1秒拍的2张照片。你的脑子肯定比我聪明,希望你的RTC做的比我的好。
图1 RTC时钟动了


部分代码(看了头真的有点晕)
//主函数
#include "stm32f10x.h"
#include "user.h"
#include "LCD.C"
#include "RTC.C"
int main(void)
{
SystemInit();
RCC_GetClocksFreq(&RCC_ClockFreq);
GPIO_Configuration();
TestLCDS();
RTC_Configuration();
Clock_Adjustment();
while (1)
{
byte_disp(5,0,' ');
byte_disp(5,1,' ');
byte_disp(5,6,((RealTime.hour)/10)+0x30);
byte_disp(5,7,((RealTime.hour)%10)+0x30);
byte_disp(5,8,':');
byte_disp(5,9,((RealTime.minute)/10)+0x30);
byte_disp(5,10,((RealTime.minute)%10)+0x30);
byte_disp(5,11,':');
byte_disp(5,12,((RealTime.second)/10)+0x30);
byte_disp(5,13,((RealTime.second)%10)+0x30);
byte_disp(4,0,' ');
byte_disp(4,1,' ');
byte_disp(4,5,'2');
byte_disp(4,6,'0');
byte_disp(4,7,((RealTime.year)/10)+0x30);
byte_disp(4,8,((RealTime.year)%10)+0x30);
byte_disp(4,9,'/');
byte_disp(4,10,((RealTime.month)/10)+0x30);
byte_disp(4,11,((RealTime.month)%10)+0x30);
byte_disp(4,12,'/');
byte_disp(4,13,((RealTime.date)/10)+0x30);
byte_disp(4,14,((RealTime.date)%10)+0x30);
}
}
//RTC函数
#include "stm32f10x.h"
void RTC2Time(void);
void TimeToRTC(T_STRUCT* time);
void Clock_Adjustment(void) ;
void RTC_IRQHandler(void);
void GetTime(T_STRUCT* time);
static u8 RTC_Blank=0;
void RTC_Configuration(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
if(BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
{
BKP_DeInit();
RCC_LSEConfig(RCC_LSE_ON);
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC_ITConfig(RTC_IT_SEC, ENABLE);
RTC_WaitForLastTask();
RTC_SetPrescaler(32776);
RTC_WaitForLastTask();
BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
RTC_Blank = 1;
}
else
{
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC2Time();
RTC_ITConfig(RTC_IT_SEC, ENABLE);
RTC_WaitForLastTask();
}
RCC_ClearFlag();
}
//----------------------------
extern const u8 Month2Day_Tab[12];
void RTC2Time(void)
{
u32 count;
u8 tmp,change = 0;
RealTime.year = BKP_ReadBackupRegister(BKP_DR2);
RealTime.month = BKP_ReadBackupRegister(BKP_DR3);
RealTime.date = BKP_ReadBackupRegister(BKP_DR4);
RealTime.day = BKP_ReadBackupRegister(BKP_DR5);
RTC_ITConfig(RTC_IT_SEC, DISABLE);
count = RTC_GetCounter();
while(count >= 0x0001517f)
{ change = 1;
count -= 0x0001517f;
if((++RealTime.day) >= 8)
RealTime.day = 1;
if(RealTime.month == 2)
{
if(RealTime.year%4)
tmp = 28;
else
tmp = 29;
}
else
{
tmp = Month2Day_Tab[RealTime.month-1];
}
if((++RealTime.date)>tmp)
{
RealTime.date = 1;
if((++RealTime.month)>12)
{
RealTime.month = 1;
if((++RealTime.year) >= 100)
{
RealTime.year = 0;
}
}
}
}
RealTime.hour = count/3600;
RealTime.minute = (count%3600)/60;
RealTime.second = (count%3600)%60;
if(change)
{
RTC_SetCounter(count);
BKP_WriteBackupRegister(BKP_DR5,RealTime.day);
BKP_WriteBackupRegister(BKP_DR4,RealTime.date);
BKP_WriteBackupRegister(BKP_DR3,RealTime.month);
BKP_WriteBackupRegister(BKP_DR2,RealTime.year);
}
RTC_ITConfig(RTC_IT_SEC, ENABLE);
}
//------------------------
void TestRtc(void)
{
if(RTC_Blank)
Clock_Adjustment();
}
//---------------------------
void TimeToRTC(T_STRUCT* time)
{
u32 count;
RTC_ITConfig(RTC_IT_SEC, DISABLE);
RTC_WaitForLastTask();
RealTime.year = time->year;
RealTime.month = time->month;
RealTime.date = time->date;
RealTime.hour = time->hour;
RealTime.minute = time->minute;
RealTime.second = time->second;
RealTime.day = time->day;
BKP_WriteBackupRegister(BKP_DR5,RealTime.day);
BKP_WriteBackupRegister(BKP_DR4,RealTime.date);
BKP_WriteBackupRegister(BKP_DR3,RealTime.month);
BKP_WriteBackupRegister(BKP_DR2,RealTime.year);
count = RealTime.hour*3600+RealTime.minute*60+RealTime.second;
RTC_WaitForLastTask();
RTC_SetCounter(count);
RTC_WaitForLastTask();
RTC_ITConfig(RTC_IT_SEC, ENABLE);
}

//--------------------------------
void Clock_Adjustment(void)
{
T_STRUCT time;
u8 d[14];
d[0]=1;
d[1]=2;
d[2]=0;
d[3]=4;
d[4]=1;
d[5]=6;
d[6]=1;
d[7]=1;
d[8]=5;
d[9]=0;
d[10]=0;
d[11]=0;
d[12]=1;
time.year = d[0]*10+d[1];
time.month = d[2]*10+d[3];
time.date = d[4]*10+d[5];
time.hour = d[6]*10+d[7];
time.minute = d[8]*10+d[9];
time.second = d[10]*10+d[11];
time.day = d[12];
TimeToRTC(&time);
}
//--------------------------
extern T_STRUCT RealTime;
void GetTime(T_STRUCT* time)
{
RTC_ITConfig(RTC_IT_SEC, DISABLE);
RTC_WaitForLastTask();
time->year = RealTime.year;
time->month = RealTime.month;
time->date = RealTime.date;
time->hour = RealTime.hour;
time->minute = RealTime.minute;
time->second = RealTime.second;
time->day = RealTime.day;
RTC_WaitForLastTask();
RTC_ITConfig(RTC_IT_SEC, ENABLE);
}
//----------------------
//中断函数
//----------------------
T_STRUCT RealTime;
void RTC_IRQHandler(void)
{
u8 tmp;
if(RTC_GetITStatus(RTC_IT_SEC) != RESET)
{
RTC_WaitForLastTask();
RTC_ClearITPendingBit(RTC_IT_SEC);
if((++RealTime.second)>59)
{
RealTime.second=0;
if((++RealTime.minute)>59)
{
RealTime.minute=0;
if((++RealTime.hour)>23)
{
RealTime.hour=0;
if((++RealTime.day)>=8)
RealTime.day=1;
BKP_WriteBackupRegister(BKP_DR5,RealTime.day);
if(RealTime.month==2)
{
if(RealTime.year%4)
tmp=28;
else
tmp=29;
}
else
{
tmp=Month2Day_Tab[RealTime.month-1];
}
if((++RealTime.date)>tmp)
{
RealTime.date = 1;
if((++RealTime.month)>12)
{
RealTime.month=1;
if((++RealTime.year)>99)
{
RealTime.year=0;
}
BKP_WriteBackupRegister(BKP_DR2,RealTime.year);
}
BKP_WriteBackupRegister(BKP_DR3,RealTime.month);
}
BKP_WriteBackupRegister(BKP_DR4,RealTime.date);
}
}
}
RTC_WaitForLastTask();
if(RTC_GetCounter() >= 0x0001517f)
RTC_SetCounter(0x0);
}
}
//-----------
//中断初始化
//-----------
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

ARM DIY进程6:Usart
串口通讯的练习,将ARM开发板的COM1与PC机的COM1连接,通讯协议设置为8位数据位,1位停止位,无奇偶校验,9600波特率。开发板上要显示的信息用fprint()发送到PC机。PC机用串口调试软件SSCOM,PC机成为一个显示终端。调试中的变量可以以十进制、十六进制、字符式在PC机上显示。
记得将options-Target-Use MicroLIB选项打勾。
图1

上图是运行结果。以后就可以用这个调试环境来跟踪变量了。
代码
#include "stm32f10x.h"
int main(void)
{
u32 a;
ChipHalInit();
ChipOutHalInit();
a=0x23;
printf("变量a用无符号十进制形式显示:%u\r\n",a);
printf("变量a用十六进制形式显示:%x\r\n",a);
printf("变量a用字符形式显示:%c\r\n",a);
while(1);
}
void USART_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
USART_ClockInitTypeDef USART_ClockInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|
RCC_APB2Periph_AFIO |
RCC_APB2Periph_USART1 ,
ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
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_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_ClockInitStructure.USART_Clock = USART_Clock_Disable;
USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;
USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;
USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;
USART_ClockInit(USART1, &USART_ClockInitStructure);
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
int fputc(int ch)
{
USART_SendData(USART1, (u8) ch);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return ch;
}

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相波形