零死角玩转stm32-高级篇1、SDIO(4bit + DMA、支持SDHC、带协议分析)

0、友情提示

《零死角玩转STM32》系列教程由初级篇、中级篇、高级篇、系统篇、四个部分组成,根据野火STM32开发板旧版教程升级而来,且经过重新深入编写,重新排版,更适合初学者,步步为营,从入门到精通,从裸奔到系统,让您零死角玩转STM32。M3的世界,与野火同行,乐意惬无边。

另外,野火团队历时一年精心打造的《STM32库开发实战指南》将于今年10月份由机械工业出版社出版,该书的排版更适于纸质书本阅读以及更有利于查阅资料。内容上会给你带来更多的惊喜。是一本学习STM32必备的工具书。敬请期待!

1、SDIO(4bit + DMA、支持SDHC)

1.1 实验描述及工程文件清单

实验描述MicroSD卡(SDIO模式)测试实验,采用4bit数据线模式。没有跑文件系统,只是单纯地读block并将测试信息通过串口

1在电脑的超级终端上打印出来。

硬件连接PC12-SDIO-CLK:CLK

PC10-SDIO-D2 :DATA2

PC11-SDIO-D3:CD/DATA3

PD2-SDIO-CMD :CMD

PC8-SDIO-D0:DATA0

PC9-SDIO-D1:DATA1

用到的库文件startup/start_stm32f10x_hd.c

CMSIS/core_cm3.c

CMSIS/system_stm32f10x.c

FWlib/stm32f10x_gpio.c

FWlib/stm32f10x_rcc.c

FWlib/stm32f10x_usart.c

FWlib/stm32f10x_sdio.c

FWlib/stm32f10x_dma.c

FWlib/misc.c

用户编写的文件USER/main.c

USER/stm32f10x_it.c

USER/usart1.c

USER/sdio_sdcard.c

野火STM32开发板 MicroSD卡硬件原理图:

1.2 SDIO简介

野火STM32开发板的CPU ( STM32F103VET6 )具有一个SDIO接口。SD/SDIO/MMC主机接口可以支持MMC卡系统规范4.2版中的3个不同的数据总线模式:1位(默认)、4位和8位。在8位模式下,该接口可以使数据传输速率达到48MHz,该接口兼容SD存储卡规范2.0版。SDIO存储卡规范2.0版支持两种数据总线模式:1位(默认)和4位。

目前的芯片版本只能一次支持一个SD/SDIO/MMC 4.2版的卡,但可以同时支持多个MMC 4.1版或之前版本的卡。除了SD/SDIO/MMC,这个接口完全与CE-ATA数字协议版本1.1兼容。

1.3 SD协议

大多数人原来没有了解过SD协议,又看到SDIO的驱动有2000多行,感觉无从下手。所以野火重新写了这个文档进行详细的解释,帮助大家更快地跨过这道槛。

附资料:《Simplified_Physical_Layer_Spec.pdf》,这个资料包含了SDIO 协议中SD存储卡的部分。

下面野火结合STM32的SDIO,分析SD协议,让大家对它先有个大概了解,更具体的说明在代码中展开。

SDIO接口图

一.从SDIO的时钟说起。

SDIO_CK时钟是通过PC12引脚连接到SD卡的,是SDIO接口与SD卡用于同步的时钟。

SDIO选配器挂载到AHB总线上,通过HCLK二分频输入到适配器得到SDIO_CK的时钟,这时SDIO_CK = HCLK/(2+CLKDIV)。其中CLKDIV是SDIO_CLK(寄存器)中的CLKDIV位。

另外,SDIO_CK也可以由SDIOCLK通过设置bypass模式直接得到,这时SDIO_CK = SDIOCLK=HCLK。

通过下面的库函数来配置时钟:

1.SDIO_Init(&SDIO_InitStructure);

对SD卡的操作一般是大吞吐量的数据传输,所以采用DMA来提高效率,SDIO采用的是DMA2中的通道4。在数据传输的时候SDIO可向DMA发出请求。

二.讲解SDIO的命令、数据传输方式。

SDIO的所有命令及命令响应,都是通过SDIO-CMD引脚来传输的。

命令只能由host即STM32的SDIO控制器发出。SDIO协议把命令分成了11种,包括基本命令,读写命令还有ACMD系列命令等。其中,在发送ACMD 命令前,要先向卡发送编号为CMD55的命令。

参照下面的命令格式图,其中的start bit,transmission bit ,crc7,endbit,都是由STM32中的SDIO硬件完成,我们在软件上配置的时候只需要设置command index和命令参数argument。Command index就是命令索引(编号),如CMD0,CMD1…被编号成0,1...。有的命令会包含参数,读命令的地址参数等,这个参数被存放在argument段。

SD卡命令格式

可以通过下面的函数来配置、发送命令:

1.SDIO_SendCommand(&SDIO_CmdInitStructure); //发送命令

SD卡对host的各种命令的回复称为响应,除了CMD0命令外,SD卡在接收到命令都会返回一个响应。对于不同的命令,会有不同的响应格式,共7种,分为长响应型(136bit)和短响应型(48bit)。以下图,响应6(R6)为例:

SD卡命令响应格式(R6)

SDIO通过CMD接收到响应后,硬件去除头尾的信息,把command index 保存到SDIO_RESPCMD寄存器,把argument field内容保存存储到

SDIO_RESPx寄存器中。这两个值可以分别通过下面的库函数得到。

1.SDIO_GetCommandResponse(); //卡返回接收到的命令

2.SDIO_GetResponse(SDIO_RESP1); //卡返回的argument field内容

数据写入,读取。请看下面的写数据时序图,在软件上,我们要处理的只是读忙。另外,我们的实验中用的是Micro SD卡,有4条数据线,默认的时候SDIO采用1条数据线的传输方式,更改为4条数据线模式要通过向卡发送命令来更改。

SD卡的多块写入时序图

三.卡的种类。

STM32的SDIO支持SD存储卡,SD I/O卡,MMC卡。

其中SDI/O卡与SD存储卡是有区别的,SDI/O卡实际上就是利用SDIO接口的一些模块,插入SD的插槽中,扩展设备的功能,如:SDI/O wifi, SDI/O cmos相机等。而SD存储卡就是我们平时常见的单纯用于存储数据的卡。

可使用SDIO接口类型的卡

本实验中使用的Micro SD卡属于SDSC(标准容量,最大两G)卡。介绍卡的种类是因为SD协议中的命令也支持这三种类型的卡,因此对STM32中的SDIO接口进行初始化后,上电后就要对接入的卡进行检测、分类,这个过程是通过向卡发送一系列不同的命令,根据卡不同的响应来进行分类。

下面进入代码展开具体讲解。

1.4 代码分析

首先要添加用的库文件,在工程文件夹下Fwlib下我们需添加以下库文件:

FWlib/stm32f10x_gpio.c

FWlib/stm32f10x_rcc.c

FWlib/stm32f10x_usart.c

FWlib/stm32f10x_sdio.c

FWlib/stm32f10x_dma.c

FWlib/misc.c

还要在stm32f10x_conf.h中把相应的头文件添加进来:

1.#include "stm32f10x_dma.h"

2.#include "stm32f10x_gpio.h"

3.#include "stm32f10x_rcc.h"

4.#include "stm32f10x_sdio.h"

5.#include "stm32f10x_usart.h"

6.#include "misc.h"

保持良好的习惯,从main函数开始分析:

1.int main(void)

2.{

3.

4./*进入到main函数前,启动文件startup(startup_stm32f10x_xx.s)已经调用

了在

5. system_stm32f10x.c中的SystemInit(),配置好了系统时钟,在外部晶振8M

的条件下,

6.设置HCLK = 72M */

7.

8./* Interrupt Config */

9. NVIC_Configuration();

10.

11./* USART1 config */

12. USART1_Config();

13.

14./*------------------------------ SD Init -------------------------

--------- */

15. Status = SD_Init();

16.

17. printf( "\r\n 这是一个MicroSD卡实验(没有跑文件系

统).........\r\n " );

18.

19.

20.if(Status == SD_OK) //检测初始化是否成功

21. {

22. printf( " \r\n SD_Init 初始化成功 \r\n " );

23. }

24.else

25. {

26. printf("\r\n SD_Init 初始化失败 \r\n" );

27. printf("\r\n 返回的Status的值为: %d \r\n",Status );

28. }

29.

30. printf( " \r\n CardType is :%d ", SDCardInfo.CardType );

31. printf( " \r\n CardCapacity is :%d ", SDCardInfo.CardCapacity );

32. printf( " \r\n CardBlockSize is :%d ", SDCardInfo.CardBlockSize )

;

33. printf( " \r\n RCA is :%d ", SDCardInfo.RCA);

34. printf( " \r\n ManufacturerID is :%d \r\n", SDCardInfo.SD_cid.Man

ufacturerID );

35.

36. SD_EraseTest(); //擦除测试

37.

38. SD_SingleBlockTest(); //单块读写测试

39.

40. SD_MultiBlockTest(); //多块读写测试

41.

42.while (1)

43. {}

44.}

main函数的流程简单明了:

1.用NVIC_Configuration()初始化好SDIO的中断;

2.用USART1_Config()配置好用于返回调试信息的串口,SD_Init()开始

进行SDIO的初始化;

3.最后分别用SD_EraseTest()、SD_SingleBlockTest()、SD_MultiBlockTest()

进行擦除,单数据块读写,多数据块读写测试。

下面我们先进入SDIO驱动函数的大头——SD_Init()进行分析:

1./*

2. * 函数名:SD_Init

3. * 描述:初始化SD卡,使卡处于就绪状态(准备传输数据)

4. * 输入:无

5. * 输出:-SD_Error SD卡错误代码

6. * 成功时则为 SD_OK

7. * 调用:外部调用

8. */

9.SD_Error SD_Init(void)

10.{

11./*重置SD_Error状态*/

12. SD_Error errorstatus = SD_OK;

13.

14./* SDIO 外设底层引脚初始化 */

15. GPIO_Configuration();

16.

17./*对SDIO的所有寄存器进行复位*/

18. SDIO_DeInit();

19.

20./*上电并进行卡识别流程,确认卡的操作电压 */

21. errorstatus = SD_PowerON();

22.

23./*如果上电,识别不成功,返回“响应超时”错误 */

24.if (errorstatus != SD_OK)

25. {

26./*!< CMD Response TimeOut (wait for CMDSENT flag) */

27.return(errorstatus);

28. }

29.

30./*卡识别成功,进行卡初始化 */

31. errorstatus = SD_InitializeCards();

32.

33.if (errorstatus != SD_OK) //失败返回

34. {

35./*!< CMD Response TimeOut (wait for CMDSENT flag) */

36.return(errorstatus);

37. }

38.

39./*!< Configure the SDIO peripheral

40.上电识别,卡初始化都完成后,进入数据传输模式,提高读写速度

41.速度若超过24M要进入bypass模式

42. !< on STM32F2xx devices, SDIOCLK is fixed to 48MHz

43. !< SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_TRANSFER_CLK_DIV) */

44. SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV;

45. SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising; //上

升沿采集数据

46. SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable; //时钟

频率若超过24M,要开启此模式

47. SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;

//若开启此功能,在总线空闲时关闭sd_clk时钟

48. SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;

//1位模式

49. SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_

Disable; //硬件流,若开启,在FIFO不能进行发送和接收数据时,数据传输暂停

50. SDIO_Init(&SDIO_InitStructure);

51.

52.if (errorstatus == SD_OK)

53. {

54./*----------------- Read CSD/CID MSD registers ------------------

*/

55. errorstatus = SD_GetCardInfo(&SDCardInfo); //用来读取csd/cid寄存

56. }

57.

58.if (errorstatus == SD_OK)

59. {

60./*----------------- Select Card --------------------------------

*/

61. errorstatus = SD_SelectDeselect((uint32_t) (SDCardInfo.RCA << 16));

//通过cmd7 ,rca选择要操作的卡

62. }

63.

64.if (errorstatus == SD_OK)

65. {

66. errorstatus = SD_EnableWideBusOperation(SDIO_BusWide_4b); //开启

4bits模式

67. }

68.

69.return(errorstatus);

70.}

先从整体上了解这个SD_Init()函数:

1.用GPIO_Configuration()进行SDIO的端口底层配置

2.分别调用了SD_PowerON()和SD_InitializeCards()函数,这两个函数共同实现了上面提到的卡检测、识别流程。

3.调用SDIO_Init(&SDIO_InitStructure)库函数配置SDIO的时钟,数据线宽度,硬件流(在读写数据的时候,开启硬件流是和很必要的,可以减少出错)

4. 调用SD_GetCardInfo(&SDCardInfo)获取sd卡的CSD寄存器中的内容,在main函数里输出到串口的数据就是这个时候从卡读取得到的。

5. 调用SD_SelectDeselect()选定后面即将要操作的卡。

6.调用SD_EnableWideBusOperation(SDIO_BusWide_4b)开启4bit数据线模式

如果SD_Init()函数能够执行完整个流程,并且返回值是SD_OK的话则说明初始化成功,就可以开始进行擦除、读写的操作了。

下面进入SD_PowerON()函数,分析完这个函数大家就能了解SDIO如何接收、发送命令了。

1./*

2. * 函数名:SD_PowerON

3. * 描述:确保SD卡的工作电压和配置控制时钟

4. * 输入:无

5. * 输出:-SD_Error SD卡错误代码

6. * 成功时则为 SD_OK

7. * 调用:在 SD_Init() 调用

8. */

9.SD_Error SD_PowerON(void)

10.{

11. SD_Error errorstatus = SD_OK;

12. uint32_t response = 0, count = 0, validvoltage = 0;

13. uint32_t SDType = SD_STD_CAPACITY;

14.

15./*!< Power ON Sequence ------------------------------------------------

-----*/

16./*!< Configure the SDIO peripheral */

17./*!< SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_INIT_CLK_DIV) */

18./*!< on STM32F2xx devices, SDIOCLK is fixed to 48MHz */

19./*!< SDIO_CK for initialization should not exceed 400 KHz */

20./*初始化时的时钟不能大于400KHz*/

21. SDIO_InitStructure.SDIO_ClockDiv = SDIO_INIT_CLK_DIV; /* HCLK = 72MHz,

SDIOCLK = 72MHz, SDIO_CK = HCLK/(178 + 2) = 400 KHz */

22. SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;

23. SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable; //不使

用bypass模式,直接用HCLK进行分频得到SDIO_CK

24. SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable; /

/ 空闲时不关闭时钟电源

25. SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b; /

/1位数据线

26. SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_

Disable;//硬件流

27. SDIO_Init(&SDIO_InitStructure);

28.

29./*!< Set Power State to ON */

30. SDIO_SetPowerState(SDIO_PowerState_ON);

31.

32./*!< Enable SDIO Clock */

33. SDIO_ClockCmd(ENABLE);

34.

35./*下面发送一系列命令,开始卡识别流程*/

36./*!< CMD0: GO_IDLE_STATE ----------------------------------------------

-----*/

37./*!< No CMD response required */

38. SDIO_CmdInitStructure.SDIO_Argument = 0x0;

39. SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_GO_IDLE_STATE; //cmd0

40. SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_No; //无响应

41. SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

42. SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; //则CPSM在开始发送

命令之前等待数据传输结束。

43. SDIO_SendCommand(&SDIO_CmdInitStructure); //写命令进命令寄存器

44.

45. errorstatus = CmdError();//检测是否正确接收到cmd0

46.

47.if (errorstatus != SD_OK) //命令发送出错,返回

48. {

49./*!< CMD Response TimeOut (wait for CMDSENT flag) */

50.return(errorstatus);

51. }

52.

53./*!< CMD8: SEND_IF_COND -----------------------------------------------

-----*/

54./*!< Send CMD8 to verify SD card interface operating condition */

55./*!< Argument: - [31:12]: Reserved (shall be set to '0')

56. - [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V)

57. - [7:0]: Check Pattern (recommended 0xAA) */

58./*!< CMD Response: R7 */

59. SDIO_CmdInitStructure.SDIO_Argument = SD_CHECK_PATTERN; //接收到命令sd

会返回这个参数

60. SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_SEND_IF_COND; //cmd8

61. SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r7

62. SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; //关闭等待中

63. SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

64. SDIO_SendCommand(&SDIO_CmdInitStructure);

65.

66./*检查是否接收到命令*/

67. errorstatus = CmdResp7Error();

68.

69.if (errorstatus == SD_OK) //有响应则card遵循sd协议2.0版本

70. {

71. CardType = SDIO_STD_CAPACITY_SD_CARD_V2_0; /*!< SD Card 2.0 ,先把它定

义会sdsc类型的卡*/

72. SDType = SD_HIGH_CAPACITY; //这个变量用作acmd41的参数,用来询问是sdsc卡

还是sdhc卡

73. }

74.else//无响应,说明是1.x的或mmc的卡

75. {

76./*!< CMD55 */

77. SDIO_CmdInitStructure.SDIO_Argument = 0x00;

78. SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;

79. SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;

80. SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

81. SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

82. SDIO_SendCommand(&SDIO_CmdInitStructure);

83. errorstatus = CmdResp1Error(SD_CMD_APP_CMD);

84. }

85./*!< CMD55 *///为什么在else里和else外面都要发送CMD55?

86.//发送cmd55,用于检测是sd卡还是mmc卡,或是不支持的卡

87. SDIO_CmdInitStructure.SDIO_Argument = 0x00;

88. SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;

89. SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r1

90. SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

91. SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

92. SDIO_SendCommand(&SDIO_CmdInitStructure);

93. errorstatus = CmdResp1Error(SD_CMD_APP_CMD); //是否响应,没响应的是mmc或

不支持的卡

94.

95./*!< If errorstatus is Command TimeOut, it is a MMC card */

96./*!< If errorstatus is SD_OK it is a SD card: SD card 2.0 (voltage rang

e mismatch)

97. or SD card 1.x */

98.if (errorstatus == SD_OK) //响应了cmd55,是sd卡,可能为1.x,可能为2.0

99. {

100./*下面开始循环地发送sdio支持的电压范围,循环一定次数*/

101.

102./*!< SD CARD */

103./*!< Send ACMD41 SD_APP_OP_COND with Argument 0x80100000 */

104.while ((!validvoltage) && (count < SD_MAX_VOLT_TRIAL))

105. {

106.//因为下面要用到ACMD41,是ACMD命令,在发送ACMD命令前都要先向卡发送CMD55

107./*!< SEND CMD55 APP_CMD with RCA as 0 */

108. SDIO_CmdInitStructure.SDIO_Argument = 0x00;

109. SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD; //CMD55 110. SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; 111. SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

112. SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

113. SDIO_SendCommand(&SDIO_CmdInitStructure);

114.

115. errorstatus = CmdResp1Error(SD_CMD_APP_CMD); //检测响应

116.

117.if (errorstatus != SD_OK)

118. {

119.return(errorstatus);//没响应CMD55,返回

120. }

121.//acmd41,命令参数由支持的电压范围及HCS位组成,HCS位置一来区分卡是SDSc 还是sdhc

122. SDIO_CmdInitStructure.SDIO_Argument = SD_VOLTAGE_WINDOW_SD | SDT ype; //参数为主机可供电压范围及hcs位

123. SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_OP_COND; 124. SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r3 125. SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

126. SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

127. SDIO_SendCommand(&SDIO_CmdInitStructure);

128.

129. errorstatus = CmdResp3Error(); //检测是否正确接收到数据

130.if (errorstatus != SD_OK)

131. {

132.return(errorstatus); //没正确接收到acmd41,出错,返回

133. }

134./*若卡需求电压在SDIO的供电电压范围内,会自动上电并标志pwr_up位*/

135. response = SDIO_GetResponse(SDIO_RESP1); //读取卡寄存器,卡状态

136. validvoltage = (((response >> 31) == 1) ? 1 : 0); //读取卡的ocr 寄存器的pwr_up位,看是否已工作在正常电压

137. count++; //计算循环次数

138. }

139.if (count >= SD_MAX_VOLT_TRIAL) //循环检测超过一定次数还没上电

140. {

141. errorstatus = SD_INVALID_VOLTRANGE; //SDIO不支持card的供电电压

142.return(errorstatus);

143. }

144./*检查卡返回信息中的HCS位*/

145.if (response &= SD_HIGH_CAPACITY) //判断ocr中的ccs位,如果是sdsc 卡则不执行下面的语句

146. {

147. CardType = SDIO_HIGH_CAPACITY_SD_CARD; //把卡类型从初始化的sdsc型改为sdhc型

148. }

149.

150. }/*!< else MMC Card */

151.

152.return(errorstatus);

153.}

这个函数的流程就是卡的上电、识别操作,如下图:

卡的上电,识别流程:

截图来自《Simplified_Physical_Layer_Spec.pdf》 page27

代码中所有的判断语句都是根据这个图的各个识别走向展开的,最终把卡分为1.0版的SD存储卡,2.0版的SDSC卡和2.0版的SDHC卡。

在这个代码流程中有两点要注意一下:

1.初始化的时钟。SDIO_CK的时钟分为两个阶段,在初始化阶段SDIO_CK 的频率要小于400KHz,初始化完成后可把SDIO_CK调整成高速模式,高速模式时超过24M要开启bypass模式,对于SD存储卡即使开启bypass,最高频率不能超过25MHz。

2.CMD8命令。

CMD8命令格式。

CMD8命令中的VHS是用来确认主机SDIO是否支持卡的工作电压的。Check pattern部分可以是任何数值,若SDIO支持卡的工作电压,卡会把接收到的check pattern数值原样返回给主机。

CMD8命令的响应格式R7:

在驱动程序中调用了CmdResp7Error()来检验卡接收命令后的响应。

3.ACMD41命令。

这个命令也是用来进一步检查SDIO是否支持卡的工作电压的,协议要它在

调用它之前必须先调用CMD8,另外还可以通过它命令参数中的HCS位来区分卡是SDHC卡还是SDSC卡。

确认工作电压时循环地发送ACMD41,发送后检查在SD卡上的OCR寄存器中的pwr_up位,若pwr_up位置为1,表明SDIO支持卡的工作电压,卡开始正常工作。

同时把ACMD41中的命令参数HCS位置1,卡正常工作的时候检测OCR寄存器中的CCS位,若CCS位为1则说明该卡为SDHC卡,为零则为SDSC卡。

因为ACMD41命令属于ACMD命令,在发送ACMD命令前都要先发送

CMD55.

ACMD41命令格式

ACMD41命令的响应(R3),返回的是OCR寄存器的值

OCR寄存器的内容

SD卡上电确认成功后,进入SD_InitializeCards()函数:

1./*

2. * 函数名:SD_InitializeCards

3. * 描述:初始化所有的卡或者单个卡进入就绪状态

4. * 输入:无

5. * 输出:-SD_Error SD卡错误代码

6. * 成功时则为 SD_OK

7. * 调用:在 SD_Init() 调用,在调用power_on()上电卡识别完毕后,调用此函数进

行卡初始化

8. */

9.SD_Error SD_InitializeCards(void)

10.{

11. SD_Error errorstatus = SD_OK;

12. uint16_t rca = 0x01;

13.

14.if (SDIO_GetPowerState() == SDIO_PowerState_OFF)

15. {

16. errorstatus = SD_REQUEST_NOT_APPLICABLE;

17.return(errorstatus);

18. }

19.

20.if (SDIO_SECURE_DIGITAL_IO_CARD != CardType)//判断卡的类型

21. {

22./*!< Send CMD2 ALL_SEND_CID */

23. SDIO_CmdInitStructure.SDIO_Argument = 0x0;

24. SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_ALL_SEND_CID;

25. SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Long;

26. SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

27. SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

28. SDIO_SendCommand(&SDIO_CmdInitStructure);

29.

30. errorstatus = CmdResp2Error();

31.

32.if (SD_OK != errorstatus)

33. {

34.return(errorstatus);

35. }

36.

37. CID_Tab[0] = SDIO_GetResponse(SDIO_RESP1);

38. CID_Tab[1] = SDIO_GetResponse(SDIO_RESP2);

39. CID_Tab[2] = SDIO_GetResponse(SDIO_RESP3);

40. CID_Tab[3] = SDIO_GetResponse(SDIO_RESP4);

41. }

42.

43./*下面开始SD卡初始化流程*/

44.if ((SDIO_STD_CAPACITY_SD_CARD_V1_1 == CardType) || (SDIO_STD_CAPAC

ITY_SD_CARD_V2_0 == CardType) || (SDIO_SECURE_DIGITAL_IO_COMBO_CARD = = CardType)

45. || (SDIO_HIGH_CAPACITY_SD_CARD == CardType)) //使用的是2.0的

46. {

47./*!< Send CMD3 SET_REL_ADDR with argument 0 */

48./*!< SD Card publishes its RCA. */

49. SDIO_CmdInitStructure.SDIO_Argument = 0x00;

50. SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_REL_ADDR; //cmd3

51. SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r6

52. SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

53. SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

54. SDIO_SendCommand(&SDIO_CmdInitStructure);

55.

56. errorstatus = CmdResp6Error(SD_CMD_SET_REL_ADDR, &rca); //把接收到

的卡相对地址存起来。

57.

58.if (SD_OK != errorstatus)

59. {

60.return(errorstatus);

61. }

62. }

63.

64.if (SDIO_SECURE_DIGITAL_IO_CARD != CardType)

65. {

66. RCA = rca;

67.

68./*!< Send CMD9 SEND_CSD with argument as card's RCA */

69. SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)(rca << 16);

70. SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_CSD;

71. SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Long;

72. SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;

73. SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

74. SDIO_SendCommand(&SDIO_CmdInitStructure);

75.

76. errorstatus = CmdResp2Error();

77.

78.if (SD_OK != errorstatus)

79. {

80.return(errorstatus);

81. }

82.

83. CSD_Tab[0] = SDIO_GetResponse(SDIO_RESP1);

84. CSD_Tab[1] = SDIO_GetResponse(SDIO_RESP2);

85. CSD_Tab[2] = SDIO_GetResponse(SDIO_RESP3);

86. CSD_Tab[3] = SDIO_GetResponse(SDIO_RESP4);

87. }

88.

89. errorstatus = SD_OK; /*!< All cards get intialized */

90.

91.return(errorstatus);

92.}

这个函数向卡发送了CMD2和CMD3命令

1.CMD2

CMD2命令是要求卡返回它的CID寄存器的内容。

命令的响应格式(R2)。

因为命令格式是136位的,属于长响应。软件接收的信息有128位。在长响应的时候通过SDIO_GetResponse(SDIO_RESP4);中的不同参数来获取CID中的不同数

据段的数据。

2.CMD3

CMD3命令是要求卡向主机发送卡的相对地址。在接有多个卡的时候,主机要求接口上的卡重新发一个相对地址,这个地址跟卡的实际ID不一样。比如接口上接了5个卡,这5个卡的相对地址就分别为1,2,3,4,5.以后主机SDIO对这几个卡寻址就直接使用相对地址。这个地址的作用就是为了寻址更加简单。

接下来我们回到SD_Init()函数。分析到这里大家应该对SDIO的命令发送和响应比较清楚了。在SD_InitializeCards()之后的SD_GetCardInfo(&SDCardInfo)、SD_SelectDeselect()和

SD_EnableWideBusOperation(SDIO_BusWide_4b)的具体实现就不再详细分析了,实际就是发送相应的命令,对卡进行相应的操作。

接下来分析main函数中的SD_MultiBlockTest()多块数据读写函数,让大家了解SDIO是怎样传输数据的。

1./*

2. * 函数名:SD_MultiBlockTest

3. * 描述:多数据块读写测试

4. * 输入:无

5. * 输出:无

6. */

7.void SD_MultiBlockTest(void)

8.{

9./*--------------- Multiple Block Read/Write ---------------------

*/

10./* Fill the buffer to send */

11. Fill_Buffer(Buffer_MultiBlock_Tx, MULTI_BUFFER_SIZE, 0x0);

12.

13.if (Status == SD_OK)

语文六大修辞手法详解

语文六大修辞手法详解 一修辞手法详解:比喻 1、定义 比喻就是“打比方”。是根据两种不同性质的事物之间的相似之处,用一种事物来比方另一种事物的修辞手法。 2、结构 比喻一般由三个部分组成,即本体(被比喻的事物或情景)、喻体(被拿来用作比喻的事物或情景)和比喻词(比喻关系的标志性词语)。 3、构成条件——注意事项 构成比喻的关键:①甲(本体)和乙(喻体)必须是本质不同的事物;②甲乙之间必须有相似之处。①②两条必须同时成立,否则比喻不能成立。 一个句子是不是比喻,不能单看比喻词。 下面几例不是比喻句: ①他的性格像母亲。——同类事物做比较 ②这天黑沉沉的好象要下雨。——表示猜测 ③不要带着思想包袱去工作。——词的比喻意 4、比喻的目的 比喻旨在于用形象的语言阐明思想。即通过比喻的手法,让人对不明白、不理解、不清楚、不认识的事物得到认识和理解。 因此,必须是用人们所熟悉的事物做喻体来比喻人们不熟悉的事物(本体),以让人对原本不认识的事物得以认识,绝不可用人们不熟悉的事物来比喻人们熟悉的事物,更不可用人们都不认识的事物去比喻人们都不认识的事物。则否适得其反,事与愿违。 比喻的具体目的主要有下面几种: ①说明本体的可能性。本体被一件令人诧异的事物所修饰,须运用比喻消除这种诧异性。例如: 残酷的战争起于片言之语,君不见熊熊烈火大多来自些微火星。 某人少时劳累老时休息,恰如一只蚂蚁,夏天努力收集食物,以便冬天坐享。 ②阐明本体的情况。本体的特性原先不为人知,用比喻加以形容,大家便一目了然。 地球圆圆的,象只橙子。 她体段柔软,仿佛生就一身藤骨。 ③阐明本体情况的程度。原先对本体的特性只有概括性的了解,经过比喻,指明了这种特性的程度。这常常是可以感觉得到的事物。例如: 病人服用了一种苦药,它仿佛就是苦瓜。 房子着了火,我仿佛觉得地狱移到了人间。 ④肯定本体的情况。叙述本体的事物须用比喻来肯定和阐明。这种情况下是用可以感知的事物来比喻理性的事物。例如: 学者的长处即使不让发挥,它也象麝香那样,被遮盖住,却不能阻止它香气四溢。 轻浮的人正在不知不觉中走向毁灭,就象飞蛾扑火那样。

子网划分基础的方法步骤详解

子网划分基础的方法步骤详解 导读:我根据大家的需要整理了一份关于《子网划分基础的方法步骤详解》的内容,具体内容:现在我们用的互联网的时间越来越多,需要掌握的网络技能也很多,那么你知道子网划分方法的方法吗?下面是我整理的一些关于子网划分方法的相关资料,供你参考。子网划分的方法大... 现在我们用的互联网的时间越来越多,需要掌握的网络技能也很多,那么你知道子网划分方法的方法吗?下面是我整理的一些关于子网划分方法的相关资料,供你参考。 子网划分的方法 大家都知道,为了确定子网,分开主机和路由器的每个接口,从而产生了几个分离的网络岛,接口端连接了这些独立的网络的端点。这些独立的网络中的每个都叫做一个子网(subnet)。 我们知道IP地址是一个4字节(共32bit)的数字,被分为4段,每段8位,段与段之间用句点分隔。为了便于表达和识别,IP地址是以十进制形式表示的如210.52.207.2,每段所能表示的十进制数最大不超过255。IP 地址由两部分组成,即网络号(Network ID)和主机号(Host ID)。网络号标识的是Internet上的一个子网,而主机号标识的是子网中的某台主机。网际地址分解成两个域后,带来了一个重要的优点:IP数据包从网际上的一个网络到达另一个网络时,选择路径可以基于网络而不是主机。在大型的网际中,这一点优势特别明显,因为路由表中只存储网络信息而不是主机信息,这样可以大大简化路由表。

子网划分的例子 网络地址:10.0.0.0;子网掩码255.255.0.0(/16) 1.子网数=2 的8次方-2=254 2.主机数=2 的16次方-2=65534 3. 有效子网?:block size=256-255=1,2,3,......; 所以第一个子网为10.1.0.0, 最后1 个为10.25 4.0.0 4.广播地址:下个子网-1.所以第一个子网和最后1 个子网的广播地址分别是10.1.25 5.255 和 10.254.255.255 5.有效主机范围是:第一个子网的主机地址是10.1.0.1 到 10.1.255.254;最后1 个是10.254.0.1 到10.254.255.254 子网划分的基础 子网划分(subnetting)的优点 1.减少网络流量 2.提高网络性能 3.简化管理 4.易于扩大地理范围 怎么样创建一个子网: 如何划分子网?首先要熟记2 的幂:2 的0 次方到9 次方的值分别 为:1,2,4,8,16,32,64,128,256和512。还有要明白的是:子网划分是借助于取走主机位,把这个取走的部分作为子网位。因此这个意味划分越多的子网,主机将越少。

推荐-stm32中定时器产生不同PWM的基本思路 精品

在stm32中利用定时器TIM调制PWM的几种方法: 说说我的学习经历:从开始接触到现在有好几个月了,但是学习还是比较的费劲,而且速度也比较的缓慢,当然相比之前还是有很大的进步,记得刚刚学习的时候,建工程都是大四学长手把手教的。废话不多说先来讲讲定时器的配置: STM32F10系列最少3个、做多有8个定时器,都是16位定时器,且相互之间是独立的,计数范围为0x0000-0xffff,最大计数值为65535.可以用于测量输入信号的脉冲长度或者产生输出波形(输出比较和PWM)分为通用定时器,高级定时器,以及看门狗定时器 下面主要讲通用定时器的配置问题: 以定时器TIM1为例:先进行函数的配置 void timer1_config() { TIM_TimeBaseInitTypDef TIM_TimeBaseStructure; //开定时器1外设时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM1,ENABLE); //计时50000次时间为50000/10M=500ms TIM_TimeBaseStructure.TIM_Period=50000 ; TIM_TimeBaseStructure.TIM_Prescaler = 720-1;//720分频 TIM_TimeBaseStructure.TIM_ClockDivision =0;//时钟分割为0; //计数模式向上计数 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure)//初始化TIM1 TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE);//开启定时器中断 TIM_Cmd(TIM1,ENABLE); //使能定时器 } 关于时间的计算问题: 外设系统时钟的频率为72M,进行720分频以后,频率f=72M/720=100khz. 如果要定时0.1s 则计数值为10000,计算公式为:时间(t)=计数值(n)/频率(f).注意计数值n介于0到65535之间 有定时器则一定会有中断发生,所以要配置中断优先级,对于中断优先 级函数配置如下: V oid nvic_config() { NVIC_InitTypDef NVIC_InitStructure; //抢占优先级为1位,从优先级为3位 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1) ; NVIC_InitStructure.NVIC_IRQChannel=TIM1_IRQn; //定义定时器1为请求通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0; //抢占式优先级为0 NVIC_InitStructure.NVIC_IRQChannelSubPriority=2; //从优先级为2 NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能中断优先级 NVIC_Init(&NVIC_InitStructure); //初始化中断 } 对于优先级中的抢占式和从优先级做如下解释: 抢占式优先级:是可以抢占的中断,比如正在执行的优先级为10的中断,突然来了一个优

电路原理图详解

电子电路图原理分析 电器修理、电路设计都是要通过分析电路原理图,了解电器的功能和工作原理,才能得心应手开展工作的。作为从事此项工作的同志,首先要有过硬的基本功,要能对有技术参数的电路原理图进行总体了解,能进行划分功能模块,找出信号流向,确定元件作用。若不知电路的作用,可先分析电路的输入和输出信号之间的关系。如信号变化规律及它们之间的关系、相位问题是同相位,或反相位。电路和组成形式,是放大电路,振荡电路,脉冲电路,还是解调电路。 要学会维修电器设备和设计电路,就必须熟练掌握各单元电路的原理。会划分功能块,能按照不同的功能把整机电路的元件进行分组,让每个功能块形成一个具体功能的元件组合,如基本放大电路,开关电路,波形变换电路等。 要掌握分析常用电路的几种方法,熟悉每种方法适合的电路类型和分析步骤。 1.交流等效电路分析法 首先画出交流等效电路,再分析电路的交流状态,即:电路有信号输入时,电路中各环节的电压和电流是否按输入信号的规律变化、是放大、振荡,还是限幅削波、整形、鉴相等。 2.直流等效电路分析法 画出直流等效电路图,分析电路的直流系统参数,搞清晶体管静态工作点和偏置性质,级间耦合方式等。分析有关元器件在电路中所处状态及起的作用。例如:三极管的工作状态,如饱和、放大、截止区,二极管处于导通或截止等。 3.频率特性分析法 主要看电路本身所具有的频率是否与它所处理信号的频谱相适应。粗略估算一下它的中心频率,上、下限频率和频带宽度等,例如:各种滤波、陷波、谐振、选频等电路。 4.时间常数分析法 主要分析由R、L、C及二极管组成的电路、性质。时间常数是反映储能元件上能量积累和消耗快慢的一个参数。若时间常数不同,尽管它的形式和接法相似,但所起的作用还是不同,常见的有耦合电路、微分电路、积分电路、退耦电路、峰值检波电路等。 最后,将实际电路与基本原理对照,根据元件在电路中的作用,按以上的方法一步步分析,就不难看懂。当然要真正融会贯通还需要坚持不懈地学习。 电子设备中有各种各样的图。能够说明它们工作原理的是电原理图,简称电路图。 电路图有两种 一种是说明模拟电子电路工作原理的。它用各种图形符号表示电阻器、电容器、开关、晶体管等实物,用线条把元器件和单元电路按工作原理的关系连接起来。这种图长期以来就一直被叫做电路图。 另一种是说明数字电子电路工作原理的。它用各种图形符号表示门、触发器和各种逻辑部件,用线条把它们按逻辑关系连接起来,它是用来说明各个逻辑单元之间的逻辑关系和整机的逻辑功能的。为了和模拟电路的电路图区别开来,就把这种图叫做逻辑电路图,简称逻辑图。 除了这两种图外,常用的还有方框图。它用一个框表示电路的一部分,它能简洁明了地说明电路各部分的关系和整机的工作原理。 一张电路图就好象是一篇文章,各种单元电路就好比是句子,而各种元器件就是组成句子的单词。所以要想看懂电路图,还得从认识单词——元器件开始。有关电阻器、电容器、电感线圈、晶体管等元器件的用途、类别、使用方法等内容可以点击本文相关文章下的各个链接,本文只把电路图中常出现的各种符号重述一遍,希望初学者熟悉它们,并记住不忘。 电阻器与电位器(什么是电位器) 符号详见图 1 所示,其中( a )表示一般的阻值固定的电阻器,( b )表示半可调或微调电阻器;( c )表示电位器;( d )表示带开关的电位器。电阻器的文字符号是“ R ”,电位器是“ RP ”,即在 R 的后面再加一个说明它有调节功能的字符“ P ”。

STM32高级定时器日记之PWM

STM32高级定时器PWM实用程序 文章来源:本站原创作者:佚名 该文章讲述了STM32高级定时器PWM实用程序. 高级定时器与通用定时器比较类似,下面是一个TIM1 的PWM 程序,TIM1是STM32唯一的高级定时器。共有4个通道有死区有互补。 先是配置IO脚: GPIO_InitTypeDef GPIO_InitStructure; /* PA8设置为功能脚(PWM) */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /*PB13 设置为PWM的反极性输出*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOB, &GPIO_InitStructure); /*开时钟PWM的与GPIO的*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); /*配置TIM1*/ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; void Tim1_Configuration(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_DeInit(TIM1); //重设为缺省值 /*TIM1时钟配置*/ TIM_TimeBaseStructure.TIM_Prescaler = 4000; //预分频(时钟分 频)72M/4000=18K TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数TIM_TimeBaseStructure.TIM_Period = 144; //装载值18k/144=125hz 就是说向上加的144便满了 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置了时钟分割不

继电器控制电路模块及原理讲解

继电器控制电路模块及原理讲解 发布: 2011-9-8 | 作者: —— | 来源:huangguohai| 查看: 564次| 用户关注: 能直接带动继电器工作的CMOS集成块电路在电子爱好者认识电路知识的的习惯中,总认为CMOS 集成块本身不能直接带动继电器工作,但实际上,部分CMOS集成块不仅能直接带动继电器工作,而且工作还非常稳定可靠。本实验中所用继电器的型号为JRC5M-DC12V微型密封的继电器(其线圈电阻为750Ω)。现将CD4066CMOS集成块带动继电器的工作原理分析如下:CD4066是一个四双向模拟开关,集成块SCR1~SCR4为控制端,用于控制四双向模拟开关的 能直接带动继电器工作的CMOS集成块电路 在电子爱好者认识电路知识的的习惯中,总认为CMOS集成块本身不能直接带动继电器工作,但实际上,部分CMOS集成块不仅能直接带动继电器工作,而且工作还非常稳定可靠。本实验中所用继电器的型号为JRC5M-D C12V微型密封的继电器(其线圈电阻为750Ω)。现将CD4066CMOS集成块带动继电器的工作原理分析如下: CD4066是一个四双向模拟开关,集成块SCR1~SCR4为控制端,用于控制四双向模拟开关的通断。当SCR1接高电平时,集成块①、②脚导通,+12V→K1→集成块①、②脚→电源负极使K1吸合;反之当SCR1输入低电平时,集成块①、②脚开路,K1失电释放,SC R2~SCR4输入高电平或低电平时状态与SCR1相同。 本电路中,继电器线圈的两端均反相并联了一只二极管,它是用来保护集成电路本身的,千万不可省去,否则在继电器由吸合状态转为释放时,由于电感的作用线圈上将产生较高的反电动势,极容易导致集成块击穿。并联了二极管后,在继电器由吸合变为释放的瞬间,线圈将通过二极管形成短时间的续流回路,使线圈中的电流不致突变,从而避免了线圈中反电动势的产生,确保了集成块的安全。 低电压下继电器的吸合措施

stm32高级定时器使用教程

STM32 高级定时器-PWM简单使用 2010-04-14 14:49:29| 分类:STM32 | 标签:|举报|字号大中小订阅高级定时器与通用定时器比较类似,下面是一个TIM1 的PWM 程序,TIM1是STM32唯一的高级定时器。共有4个通道有死区有互补。 先是配置IO脚: GPIO_InitTypeDef GPIO_InitStructure; /* PA8设置为功能脚(PWM) */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /*PB13 设置为PWM的反极性输出*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); /*开时钟PWM的与GPIO的*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); /*配置TIM1*/ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure;

开关电源入门必读:开关电源工作原理超详细解析

开关电源入门必读:开关电源工作原理超详细解析 第1页:前言:PC电源知多少 个人PC所采用的电源都是基于一种名为“开关模式”的技术,所以我们经常会将个人PC电源称之为——开关电源(Sw itching Mode P ow er Supplies,简称SMPS),它还有一个绰号——DC-DC转化器。本次文章我们将会为您解读开关电源的工作模式和原理、开关电源内部的元器件的介绍以及这些元器件的功能。 ●线性电源知多少 目前主要包括两种电源类型:线性电源(linear)和开关电源(sw itching)。线性电源的工作原理是首先将127 V或者220V市电通过变压器转为低压电,比如说12V,而且经过转换后的低压依然是AC交流电;然后再通过一系列的二极管进行矫正和整流,并将低压AC交流电转化为脉动电压(配图1和2中的“3”);下一步需要对脉动电压进行滤波,通过电容完成,然后将经过滤波后的低压交流电转换成DC直流电(配图1和2中的“4”);此时得到的低压直流电依然不够纯净,会有一定的波动(这种电压波动就是我们常说的纹波),所以还需要稳压二极管或者电压整流电路进行矫正。最后,我们就可以得到纯净的低压DC直流电输出了(配图1和2中的“5”) 配图1:标准的线性电源设计图

配图2:线性电源的波形 尽管说线性电源非常适合为低功耗设备供电,比如说无绳电话、PlayStation/W ii/Xbox等游戏主机等等,但是对于高功耗设备而言,线性电源将会力不从心。 对于线性电源而言,其内部电容以及变压器的大小和AC市电的频率成反比:也即说如果输入市电的频率越低时,线性电源就需要越大的电容和变压器,反之亦然。由于当前一直采用的是60Hz(有些国家是50Hz)频率的AC市电,这是一个相对较低的频率,所以其变压器以及电容的个头往往都相对比较大。此外,AC市电的浪涌越大,线性电源的变压器的个头就越大。 由此可见,对于个人PC领域而言,制造一台线性电源将会是一件疯狂的举动,因为它的体积将会非常大、重量也会非常的重。所以说个人PC用户并不适合用线性电源。 ●开关电源知多少 开关电源可以通过高频开关模式很好的解决这一问题。对于高频开关电源而言,AC输入电压可以在进入变压器之前升压(升压前一般是50-60KHz)。随着输入电压的升高,变压器以及电容等元器件的个头就不用像线性电源那么的大。这种高频开关电源正是我们的个人PC以及像VCR录像机这样的设备所需要的。需要说明的是,我们经常所说的“开关电源”其实是“高频开关电源”的缩写形式,和电源本身的关闭和开启式没有任何关系的。 事实上,终端用户的PC的电源采用的是一种更为优化的方案:闭回路系统(closed loop system)——负责控制开关管的电路,从电源的输出获得反馈信号,然后根据PC的功耗来增加或者降低某一周期内的电压的频率以便能够适应电源的变压器(这个方法称作PW M,Pulse W idth Modulation,脉冲宽度调制)。所以说,开关电源可以根据与之相连的耗电设备的功耗的大小来自我调整,从而可以让变压器以及其他的元器件带走更少量的能量,而且降低发热量。 反观线性电源,它的设计理念就是功率至上,即便负载电路并不需要很大电流。这样做的后果就是所有元件即便非必要的时候也工作在满负荷下,结果产生高很多的热量。 第2页:看图说话:图解开关电源 下图3和4描述的是开关电源的PW M反馈机制。图3描述的是没有PFC(P ow er Factor Correction,功率因素校正)电路的廉价电源,图4描述的是采用主动式PFC设计的中高端电源。 图3:没有PFC电路的电源 图4:有PFC电路的电源 通过图3和图4的对比我们可以看出两者的不同之处:一个具备主动式PFC电路而另一个不具备,前者没有110/220V转换器,而且也没有电压倍压电路。下文我们的重点将会是主动式PFC电源的讲解。

(完整版)子网划分与VLAN技术详解

子网划分与VLAN技术详解 子网划分 子网划分定义:Internet组织机构定义了五种IP地址,有A、B、C三类地址。A类网络有126个,每个A类网络可能有16777214台主机,它们处于同一广播域。而在同一广播域中有这么多结点是不可能的,网络会因为广播通信而饱和,结果造成16777214个地址大部分没有分配出去。可以把基于类的IP网络进一步分成更小的网络,每个子网由路由器界定并分配一个新的子网网络地址,子网地址是借用基于类的网络地址的主机部分创建的。划分子网后,通过使用掩码,把子网隐藏起来,使得从外部看网络没有变化,这就是子网掩码。 子网掩码 RFC 950定义了子网掩码的使用,子网掩码是一个32位的2进制数,其对应网络地址的所有位置都为1,对应于主机地址的所有位都置为0。由此可知,A类网络的默认子网掩码是255.0.0.0,B类网络的默认子网掩码是255.255.0.0,C类网络的默认子网掩码是255.255.255.0。将子网掩码和IP地址按位进行逻辑“与”运算,得到IP地址的网络地址,剩下的部分就是主机地址,从而区分出任意IP地址中的网络地址和主机地址。子网掩码常用点分十进制表示,我们还可以用网络前缀法表示子网掩码,即“/<网络地址位数>”。如138.96.0.0/16表示B类网络138.96.0.0的子网掩码为255.255.0.0。 路由器判断IP 子网掩码告知路由器,地址的哪一部分是网络地址,哪一部分是主机地址,使路由器正确判断任意IP地址是否是本网段的,从而正确地进行路由。例如,有两台主机,主机一的IP 地址为222.21.160.6,子网掩码为255.255.255.192,主机二的IP地址为222.21.160.73,子网掩码为255.255.255.192。现在主机一要给主机二发送数据,先要判断两个主机是否在同一网段。 主机一 222.21.160.6即:11011110.00010101.10100000.00000110 255.255.255.192即:11111111.11111111.11111111.11000000 按位逻辑与运算结果为:11011110.00010101.10100000.00000000 主机二 222.21.160.73 即:11011110.00010101.10100000.01001001 255.255.255.192即:11111111.11111111.11111111.11000000 按位逻辑与运算结果为:11011110.00010101.10100000.01000000 两个结果不同,也就是说,两台主机不在同一网络,数据需先发送给默认网关,然后再发送给主机二所在网络。那么,假如主机二的子网掩码误设为255.255.255.128,会发生什么情况呢? 让我们将主机二的IP地址与错误的子网掩码相“与”: 222.21.160.73 即:11011110.00010101.10100000.01001001 255.255.255.128即:11111111.11111111.11111111.10000000 结果为11011110.00010101.10100000.00000000 这个结果与主机一的网络地址相同,主机一与主机二将被认为处于同一网络中,数据不

STM32的PWM精讲

STM32的PWM精讲 通过对TM1定时器进行控制,使之各通道输出插入死区的互补PWM输出,各通道输出频率均为17.57KHz。其中,通道1输出的占空比为50%,通道2输出的占空比为25%,通道3输出的占空比为12.5%。各通道互补输出为反相输出。 TM1定时器的通道1到4的输出分别对应PA.08、PA.09、PA.10和PA.11 引脚,而通道1到3的互补输出分别对应PB.13、PB.14和PB.15引脚,中止输入引脚为PB.12。将这些引脚分别接入示波器,在示波器上观查相应通道占空比的方波[12]。 配置好各通道后,编译运行工程;点击MDK的Debug菜单,点击Start/Stop Debug Session;通过示波器察看 PA.08、PA.09、PA.10、PB.13、PB.14、PB.15 的输出波形,其中PA.08和PB.13为第一通道和互补通道,PB.09和PB.14为第二通道和其互补通道,PB.10和PB.15为第三通道和其互补通道;第一通道显示占空比为50%,第二通道占空比为25%,第三通道占空比为12.5%。 第2章STM32处理器概述 STM32F103xx增强型系列产品中内置了多达3个同步的标准定时器。每个定时器都有一个16位的自动加载递加/递减计数器、一个16位的预分频器和4个独立的通道,每个通道都可用于输入捕获、输出比较、PWM和单脉冲模式输出,在最大的封装配置中可提供最多12个输入捕获、输出比较或PWM通道。它们还能通过定时器链接功能与高级控制定时器共同工作,提供同步或事件链接功能。 在调试模式下,计数器可以被冻结。任一个标准定时器都能用于产生PWM 输出。每个定时器都有独立的DMA请求机制。 2.4.2 高级控制定时器[22] 高级控制定时器(TM1)由一个16位的自动装载计数器组成,它由一个可编程预分频器驱动。它适合多种用途,包含测量输入信号的脉冲宽度(输入捕获),或者产生输出波形(输出比较,PWM,嵌入死区时间的互补PWM等)。 使用定时器预分频器和RCC时钟控制预分频器,可以实现脉冲宽度和波形周期从几个微秒至几个毫秒的调节。高级控制(TIM1)和通用(TMx)定时器是完全

修辞手法的讲解

小升初修辞手法 ★小学阶段修辞方法有:比喻、拟人、夸张、排比、反问、设问、对比、对偶、引用、双关1、比喻:就是打比方,是利用根本不同的两种事物之间的相似点作比的修辞手法。基本结构:本体+比喻词+喻体。常用的比喻词有:好像仿佛像……似的如同成了宛如比喻由三部分构成1、本体2、喻体3、比喻词 (比喻和拟人最大的不同在于比喻含有喻体,拟人没有。) 作用:将表达的内容说得生动具体形象,给人以鲜明深刻的印象,根据事物的相似点,用具体、浅显、常见的事物对深奥生疏的事物解说,即打比方,帮助人深入理解。 例句:活跃了一天的太阳,依旧像一个快乐的孩童。 比喻一般分为三种:明喻、暗喻、借喻。 (1)明喻是本体、喻体、比喻词都出现。如:共产党像太阳。 (2)暗喻是本体、喻体都出现,比喻词常用“是、变成、成了、构成”等。如:弟弟成了泥了。 (3)借喻是借用喻体代替本体,即只出现喻体,本体和比喻词均不出现。如:落光了叶子的柳树上挂满了毛茸茸、亮晶晶的“银条儿”。 例:在阳光的照耀下,漫山的山茶花仿佛千万颗红星在闪闪发光。 2、拟人:把物当做人写,赋予物以人的思想、感情、活动,用描写人的词来描写物。 作用:使具体事物人格化,语言生动形象有趣。 例句: 1.桃树、杏树、梨树、你不让我,我不让你,都开满了花赶趟儿。 2.感时花溅泪,恨别鸟惊心。《春望》杜甫 3.太阳的脸红起来了。《春》朱自清 拟人有两种类型:一是把事物直接当做人来描写。如:古老的威尼斯又沉沉地入睡了;二是人直接同事物说话。如:延安,你的精神灿烂辉煌!如果一旦失去了你啊,那就仿佛没有了灵魂,怎能向美好的未来展翅飞翔 例:淘气的小闹钟每天准时把我叫醒。 3、夸张:对事物的性质,特征等故意地夸张或缩小。是一种对事物作"言过其实"的描述的修辞手法。 作用:提示事物本质,烘托气氛,加强渲染力,引起联想效果。 例句:柏油路晒化了,甚至铺户门前的铜牌好像也要晒化。只能看到巴掌大的一块天地。她还没有端酒怀,就醉了。 夸张可分为三类,即扩大夸张、缩小夸张和超前夸张。

子网的划分经典例题解析

1个C类地址,地址段为192.168.8.0/24,划分8个子网主机数5,5,13,25,24,26,48,50。请划分子网和子网掩码? 首先明确一点,子网中最大主机数都是2的倍数,因为是【0000 0000】--【1111 1111】,所以一个子网的最大主机个数为2,4,8,16,32,64,128……(就是2的1次方,2的2次方,以此类推) 明白上面一点后按照题目要求,找到题目中主机数与上述最大主机数最接近的两个中较大的一个: 举例说,48这个主机数,和他最接近的应该是32和64,那么我们要取64就可以了。(如果比他小,那岂不是这48个主机要分成两个子网了么) 按照上面的方法,列出题目中给出主机数对应的最大主机数对照表 对照上述表格可以看出,A-F把最大子网数相加为128,G-H相加也是128,刚好是256/2的结果 所以首先要分成两个大的子网128个主机一个子网 192.168.8.0000 0000 192.168.8.0/25 192.168.8.1000 0000 192.168.8.128/25 那G和H就好办了,64=128/2,所以G和H就是上面两个子网任意取其中一个,再分成一半分别给G和H就好了比如我们取第一行192.168.8.0/25段给G和H: G:192.168.8.0000 0000 192.168.8.0/26 H:192.168.8.0100 0000 192.168.8.64/26 剩下的就是A-F了 A+B+C的子网数是32,和DEF的子网数相等,这样就是4个32主机数的子网了 所以,我们把上面第二行的子网192.168.8.128/25再分成4个32主机数的子网好了 4个子网,就是要有4中变化,用二进制表示就00 ,01,10,11 ;所以,4个子网如下 A-C:192.168.8.1000 0000 192.168.8.128/27 D: 192.168.8.1010 0000 192.168.8.160/27

STM32学习笔记通用定时器PWM输出

STM32学习笔记(5):通用定时器PWM输出 2011年3月30日TIMER输出PWM 1.TIMER输出PWM基本概念 脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制。一般用来控制步进电机的速度等等。 STM32的定时器除了TIM6和TIM7之外,其他的定时器都可以用来产生PWM输出,其中高级定时器TIM1和TIM8可以同时产生7路的PWM输出,而通用定时器也能同时产生4路的PWM输出。 1.1PWM输出模式 STM32的PWM输出有两种模式,模式1和模式2,由TIMx_CCMRx寄存器中的OCxM位确定的(“110”为模式1,“111”为模式2)。模式1和模式2的区别如下: 110:PWM模式1-在向上计数时,一旦TIMx_CNTTIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。 111:PWM模式2-在向上计数时,一旦TIMx_CNTTIMx_CCR1时通道1为有效电平,否则为无效电平。 由此看来,模式1和模式2正好互补,互为相反,所以在运用起来差别也并不太大。 而从计数模式上来看,PWM也和TIMx在作定时器时一样,也有向上计数模式、向下计数模式和中心对齐模式,关于3种模式的具体资料,可以查看《STM32参考手册》的“14.3.9 PWM模式”一节,在此就不详细赘述了。 1.2PWM输出管脚 PWM的输出管脚是确定好的,具体的引脚功能可以查看《STM32参考手册》的“8.3.7 定时器复用功能重映射”一节。在此需要强调的是,不同的TIMx有分配不同的引脚,但是考虑到管脚复用功能,STM32提出了一个重映像的概念,就是说通过设置某一些相关的寄存器,来使得在其他非原始指定的管脚上也能输出PWM。但是这些重映像的管脚也是由参考手册给出的。比如

STM32 高级定时器-PWM简单使用

STM32 高级定时器-PWM简 单使用 高级定时器与通用定时器比较类似,下面是一个TIM1 的PWM 程序,TIM1是STM32唯一的高级定时器。共有4个通道有死区有互补。 先是配置IO脚: GPIO_InitTypeDef GPIO_InitStructure; /* PA8设置为功能脚(PWM) */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /*PB13 设置为PWM的反极性输出*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); /*开时钟PWM的与GPIO的*/ RCC_APB2PeriphClockCmd(RCC_A PB2Periph_TIM1,ENABLE); RCC_APB2PeriphClockCmd(RCC_A PB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_A PB2Periph_GPIOB, ENABLE); /*配置TIM1*/ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; void Tim1_Configuration(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_DeInit(TIM1); //重设为缺省值 /*TIM1时钟配置*/ TIM_TimeBaseStructure.TIM_Prescaler = 4000; //预分频(时钟分频)72M/4000=18K TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数 TIM_TimeBaseStructure.TIM_Period = 144; //装载值18k/144=125hz 就是说向上加的144便满了 TIM_TimeBaseStructure.TIM_ClockDivision =

语文各种修辞手法的详解

小学语文修辞手法的详解 修辞方法不只是小学语文非常重要的基础知识,而且这一知识点的掌握好与坏直接关系到作文这一重要的知识,所以绝 不能忽视。 什么是修辞手法: 修辞手法,就是通过修饰、调整语句,运用特定的表达形式以提高语言表达作用的方式或方法,使语言表达得准确、鲜明而生动有力。 语文中的修辞手法: 比喻、拟人、夸张、排比、对偶、借代、反问、设问、对比、反复、双关、引用、反语、联想、通感、顶真、互文、回环、移情、拈连、象征、寄寓(寄托),呼告等。 常用的八种修辞手法: 比喻、拟人、夸张、排比、对偶、借代、反问、设问。

一、比喻: 1、什么是比喻 比喻就是“打比方”,即利用不同事物之间的某些相似之处,用一个事物来比方另一个事物。多用一些具体的,浅显的、熟知的事物来说明抽象的、深奥的、生疏的事物。其中比喻可以分为:明喻、暗喻、借喻、博喻(又名复喻)、倒喻(又名逆喻)、反喻、互喻(又名回喻)、较喻(可分为强喻,弱喻)、譬喻、饰喻、引喻、隐喻。 2、比喻必须具备的三个要素 (1)本体:即被比方的事物; (2)喻体:即用来作比方的事物; (3)比喻词:用来表示比喻关系的词。常见的比喻词 主要有:像、好像、若、似、似的、似乎、好似、恰似、如、犹如、有如、仿佛、好比、一样、成了、是、变成等。 3、如何判断一个句子是否是比喻句 虽然有些句子含有上述比喻词,但未必就是比喻句。判断一个句子是否是比喻句,除判断句子是否有三个要素以外,还要重点注意: 本体和喻体必须是本质不同的事物。

4、典型例句 (1)桂林的山真秀啊,像翠绿的屏障,像新生的竹笋,色彩明丽,倒映水中。《(桂林山水)》 (2)小兴安岭一年四季景色诱人,是一座美丽的大花园,也是一座巨大的宝库。《美丽的小兴安岭》 二、拟人: 1、什么是拟人 把物当做人写,赋予物以人的动作、行为、思想、语言、感情、活动,用描写人的词来描写物。 2、判断要点: 描写人的词来描写物。 3、拟人的作用 作用:把禽兽鸟虫花草树木或其他无生命的事物当成人写,使具体事物人格化,语言生动形象。将什么赋予生命,生动形象地写出某事物某特征,表达作者某情感。 4、典型例句 (1)风儿轻轻地唱着歌,唤醒了沉睡中的大地。

STM32-PWM输出总结讲课讲稿

学习后发现stm32的定时器功能确实很强大,小总结一下方便以后使用的时候做参考。Stm32定时器一共分为三种:tim1和tim8是高级定时器,6和7是基本定时器,2—5是通用定时器。从名字就可以看得出来主要功能上的差异。今天我主要是用定时器做pwm输出,所以总结也主要是针对pwm方面的。 先大致说下通用和高级定时器的区别。通用的可以输出四路pwm信号互不影响。高级定时器可以输出三对互补pwm信号外加ch4通道,也就是一共七路。 所以这样算下来stm32一共可以生成4*5+7*2=30路pwm信号。接下来还有功能上的区别:通用定时器的pwm信号比较简单,就是普通的调节占空比调节频率(别的不常用到的没去深究);高级定时器的还带有互补输出功能,同时互补信号可以插入死区,也可以使能刹车功能,从这些看来高级定时器的pwm天生就是用来控制电机的。 Pwm输出最基本的调节就是频率和占空比。频率当然又和时钟信号扯上了关系。高级定时器是挂接到APB2上,而通用定时器是挂接到APB1上的。APB1和APB2的区别就要在于时钟频率不同。APB2最高频率允许72MH,而APB1最高频率为36MHZ。这样是不是通用定时器只最高36MHZ频率呢,不是的;通用定时器时钟信号完整的路线应该是下面这样的:AHB(72mhz)→APB1分频器(默认2)→APB1时钟信号(36mhz)→倍频器(*2倍)→通用定时器时钟信号(72mhz)。 在APB1和定时器中间的倍频器起到了巨大的作用,假如红色字体的“APB1分频器”假如不为1(默认是2),倍频器会自动将APB1时钟频率扩大2倍后作为定时器信号源,这个它内部自动控制的不用配置。设置这个倍频器的目的很简单就是在APB1是36mhz的情况下通用定时器的频率同样能达到72mhz。我用的库函数直接调用函数SystemInit(); 这个函数之后时钟配置好了:通用定时器和高级定时器的时钟现在都是72mhz(你也可以自己再配置一下RCC让他的频率更低,但是不能再高了)。定时器接下来还有一个分频寄存器:TIMX_PSC 经过他的分频后,才是定时器计数的频率。所以真正的时钟频率应该是72mhz/(TIMX_PSC-1),我们设为tim_frepuency下面还会用到。 stm32的时钟频率弄得确实是很饶人的,所以关键就是先要把思路理清楚。时钟的频率弄好了下面终于可以开说重点PWM了。当然还少不了频率:pwm主要就是控制频率和占空比的:这两个因素分别通过两个寄存器控制:TIMX_ARR和TIMX_CCRX。ARR寄存器就是自动重装寄存器,也就是计数器记到这个数以后清零再开始计,这样pwm的频率就是tim_frequency/(TIMX_ARR-1)。在计数时会不停的和CCRX寄存器中的数据进行比较,如果小于的话是高电平或者低电平,计数值大于CCRX值的话电平极性反相。所以这也就控制了占空比。 下面是定时器1的配置代码: GPIO_InitTypeDef GPIO_InitStructure2; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; //第一步:配置时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA| RCC_APB2Periph_GPIOB|RCC_APB2Periph_TIM1 ,ENABLE); //第二步,配置goio口 /********TIM1_CH1 引脚配置*********/

相关文档
最新文档