目录
一、下载安装AD
下面是两种安装方法,可以任意选择一种自己喜欢的
1.1安装方法一
可以在微信上搜索“软件安装站”公众号然后关注,再点进去软件目录去找到Altium Designer选择喜欢的版本去下载。
里面有网盘的链接,和详细下载步骤,安装中如果有问题可以直接问客服
可以通过这种方式下载,这个“软件安装站”有详细教程而且如果安装过程中出现问题可以直接询问人工客服或者要求客服远程协助安装,可以说这个真的很方便了,不是打广告只是这个公众号实在是太好用了。但是里面的有的版本可能没有更新。
1.2安装方法二
可以直接参考以下博客,步骤很详细!但是还是建议选择安装方法一,因为可能会出问题,可以随时找客服问。
(74条消息) Altium Designer(AD)安装教程_Joshua Lee的博客-CSDN博客_ad安装教程
二、绘制STM32最小系统原理图
2.1元件库
用AD以来到各个地方下载的元件库,几乎常用的是没什么缺的了。都在下面的网盘里了,可能有点大:
链接:https://pan.baidu.com/s/1hTUUYVnjF_AfY-j3w2TMyQ
提取码:j7w4
2.2新建工程
安装好之后就是新建一个PCB工程
点击文件——>新的——>项目
然后
这样就创建好工程了,然后在工程里创建元件库和原理图等
创建原理图:(创建完后就直接按ctrl+S保存在刚才的工程目录下面,名字最好和工程名一样,但是自带的后缀名不能改)
创建元件库:(创建完后就直接按ctrl+S保存在刚才的工程目录下面,名字最好和工程名一样,但是自带的后缀名不能改)
元件库里面的元件可以选择自己画或者是从其他的地方复制过来,粘贴的时候注意是点击空白处进行粘贴
2.3绘制原理图
在 建好工程,导入好元件之后就可以进行原理图的绘制了
在元件库上点击“放置”就可以将元件从元件库放置到原理图上了(左键点击一下就放下了,然后右键点击一下释放掉挂着的元件)
放置好元件后,可以双击元件或者点击元件然后再按tab键进入设置窗口,编辑编号名称等东西:
元件放置完成后连线时点击上面的双波浪图案,右击可以选择多种连接方式,一般用的只有线、网络标签:
电源这些的选择在就是连线图案的旁边:(右击可以选择不同的电源,有接地等)
通过以上的学习,应该差不多已经掌握了AD的用法啦!
注意!如果还是感觉比较迷糊,那么祭出B站大佬的AD教学视频(这个视频及其详细,手把手教AD用法,但是相对时长较长,如果只画原理图建议只看前半部分就好)
Altium Designer 20 19(入门到精通全38集)四层板智能车PCB设计视频教程AD19 AD20 凡亿_哔哩哔哩_bilibili
下面就是绘制原理图了:
stm32最小系统电路原理图:
指示灯:
排针:
电源:
程序烧录/调试接口:
下载方式选择:
降压电路:
去耦电路:
晶振电路:
SD卡原理图:
总原理图:
SD卡连接STM32连接图:
三、SD卡协议原理
3.1SD卡简介
SD卡(secure digital card
)是SD卡协会开发的低成本,非易失性存储卡格式(相比较于RAM,SD卡掉电数据不丢失);
随着本世纪电子技术的高速发展,对于这种中等型号,节能、节省空间的存储器设备的需求一直在快速增长;
SD卡具有SDHC的速度等级,范围;2级(以2 MB / s的速度运行);4级(以4MB / s的速度运行);6级(以最高6 MB / s的速度运行);10级(以最高的速度运行) 10 MB /秒;
SDXC卡以超高速运行,并以最高30 Mb/s的速度运行;还有视频速度等级,数据传输速率高达90MB/s。
3.2SD卡接口
SD卡可以在SD总线模式或SPI总线模式下运行,通常可以使用SDIO总线或者SPI对SD进行驱动;下面主要以micro SD为例,就SDIO模式和SPI模式做简单做一下介绍;
microSD引脚输出,SD模式
引脚 | 引脚名称 | 信号功能 |
---|---|---|
1 | DAT2 | 数据位2 |
2 | CD / DAT3 | 卡检测/数据位3 |
3 | CMD | 命令行 |
4 | Vdd | 电源电压2.7v / 3.6v |
5 | Clk | 时钟 |
6 | VS | 地 |
7 | DAT0 | 数据位0 |
8 | DAT1 | 数据位1 |
microSD引脚输出,SPI模式
引脚 | 引脚名称 | 信号功能 |
---|---|---|
1 | NC | 没有连接 |
2 | /CS | 片选 |
3 | DI | 主输出/从属(MOSI) |
4 | Vdd | 电源电压2.7v / 3.6v |
5 | Clk | 时钟 |
6 | Vss | 地 |
7 | DO | 主进/从出(MISO) |
8 | RSV | 已预留 |
3.3协议
SD协议中,由于命令数据线和数据线是分开的,因此我们需要关注,命令的传输格式,以及数据的传输格式;
命令传输
命令以48位数据包的形式通过双向CMD引脚进行传输。
这些命令包包括命令索引,变量和CRC位。该命令始终通过主机发送,最终由SD卡接收。
回传的响应数据包也为48位。
整体命令如下图所示;
48位的命令格式
每个命令的恒定长度为6个字节。第一个字节是命令编号和数字64的 加法。例如:对于CMD0:命令编号0 + 64 = 64 = 0x40(十六进制)。
对于CMD1:十六进制命令号1 + 64 = 65 = 0x41。
随后是一组四个字节,称为参数。
四、STM32对SD卡的数据读取
4.1准备工作
准备SD卡模块和SD卡
内部结构:
STM32与SD卡模块的连线:
stm32 | SD卡模块 |
---|---|
PA4 | SDCS |
PA5 | SCK |
PA7 | MOSI |
PA6 | MISO |
VCC | VCC |
GND | GND |
连好了如图所示:
因为STM要连接SD卡模块,所以之后进行的就是HAL库配置:
然后把工程地址这些改改就可以导出了
4.2代码
main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "fatfs.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "SDdriver.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi1;
UART_HandleTypeDef huart1;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (unsigned char *)&ch, 1, 0xFFFF);
return ch;
}
uint16_t uart_value[3];
uint8_t aRxBuffer1; //uart rx buff
void WritetoSD(BYTE write_buff[],uint8_t bufSize);
char SD_FileName[] = "hello.txt";
uint8_t WriteBuffer[] = "01 write buff to sd \r\n";
//uint8_t test_sd =0; //ÓÃÓÚ²âÊÔ¸ñʽ»¯
uint8_t write_cnt =0; //дSD¿¨´ÎÊý
void WritetoSD(BYTE write_buff[],uint8_t bufSize)
{
FATFS fs;
FIL file;
uint8_t res=0;
UINT Bw;
res = SD_init(); //SD卡初始化
if(res == 1)
{
printf("SD卡初始化失败! \r\n");
}
else
{
printf("SD卡初始化成功!恭喜 \r\n");
}
res=f_mount(&fs,"0:",1); //挂载
// if(test_sd == 0) //用于测试格式化
if(res == FR_NO_FILESYSTEM) //没有文件系统,格式化
{
// test_sd =1; //用于测试格式化
printf("没有文件系统! \r\n");
res = f_mkfs("", 0, 0); //格式化sd卡
if(res == FR_OK)
{
printf("格式化成功! \r\n");
res = f_mount(NULL,"0:",1); //格式化后取消挂载
res = f_mount(&fs,"0:",1); //重新挂载
if(res == FR_OK)
{
printf("SD卡已经成功挂载,可以进进行文件写入测试!\r\n");
}
}
else
{
printf("格式化失败! \r\n");
}
}
else if(res == FR_OK)
{
printf("挂载成功!\r\n");
}
else
{
printf("挂载失败!\r\n");
}
res = f_open(&file,SD_FileName,FA_OPEN_ALWAYS |FA_WRITE);
if((res & FR_DENIED) == FR_DENIED)
{
printf("卡存储已满,写入失败!\r\n");
}
f_lseek(&file, f_size(&file));//确保写词写入不会覆盖之前的数据
if(res == FR_OK)
{
printf("打开成功/创建文件成功! \r\n");
res = f_write(&file,write_buff,bufSize,&Bw); //写数据到SD卡
if(res == FR_OK)
{
printf("文件写入成功! \r\n");
}
else
{
printf("文件写入失败! \r\n");
}
}
else
{
printf("打开文件失败!\r\n");
}
f_close(&file); //关闭文件
f_mount(NULL,"0:",1); //取消挂载
}
void Get_SDCard_Capacity(void)
{
FRESULT result;
FATFS FS;
FATFS *fs;
DWORD fre_clust,AvailableSize,UsedSize;
uint16_t TotalSpace;
uint8_t res;
res = SD_init(); //SD¿¨³õʼ»¯
if(res == 1)
{
printf("SD¿¨³õʼ»¯Ê§°Ü! \r\n");
}
else
{
printf("SD¿¨³õʼ»¯³É¹¦£¡ \r\n");
}
/* ¹ÒÔØ */
res=f_mount(&FS,"0:",1); //¹ÒÔØ
if (res != FR_OK)
{
printf("FileSystem Mounted Failed (%d)\r\n", result);
}
res = f_getfree("0:", &fre_clust, &fs); /* ¸ùĿ¼ */
if ( res == FR_OK )
{
TotalSpace=(uint16_t)(((fs->n_fatent - 2) * fs->csize ) / 2 /1024);
AvailableSize=(uint16_t)((fre_clust * fs->csize) / 2 /1024);
UsedSize=TotalSpace-AvailableSize;
/* Print free space in unit of MB (assuming 512 bytes/sector) */
printf("\r\n%d MB total drive space.\r\n""%d MB available.\r\n""%d MB used.\r\n",TotalSpace, AvailableSize,UsedSize);
}
else
{
printf("Get SDCard Capacity Failed (%d)\r\n", result);
}
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SPI1_Init();
MX_FATFS_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1,&aRxBuffer1,1); //enable uart
printf(" main \r\n");
Get_SDCard_Capacity(); //µÃµ½Ê¹ÓÃÄڴ沢ѡÔñ¸ñʽ»¯
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
WritetoSD(WriteBuffer,sizeof(WriteBuffer));
HAL_Delay(500);
WriteBuffer[0] = WriteBuffer[0] +10;
WriteBuffer[1] = WriteBuffer[1] +10;
write_cnt ++;
while(write_cnt > 10)
{
printf(" while \r\n");
HAL_Delay(500);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief SPI1 Initialization Function
* @param None
* @retval None
*/
static void MX_SPI1_Init(void)
{
/* USER CODE BEGIN SPI1_Init 0 */
/* USER CODE END SPI1_Init 0 */
/* USER CODE BEGIN SPI1_Init 1 */
/* USER CODE END SPI1_Init 1 */
/* SPI1 parameter configuration*/
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SPI1_Init 2 */
/* USER CODE END SPI1_Init 2 */
}
/**
* @brief USART1 Initialization Function
* @param None
* @retval None
*/
static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : SD_CS_Pin */
GPIO_InitStruct.Pin = SD_CS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(SD_CS_GPIO_Port, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
4.3烧录效果
现将编译好的hex文件烧进芯片里
然后改变跳线帽,打开串口调试助手,第一次烧录只显示了一个Main.
第n次:而且只有每次接上电的一瞬间才回接收到
然后把所有线全部用力插一次。。。。再换一个野火调试串口
五、总结
这个实验把我心态都整崩了啊,这个串口到底怎么怎么回事,实验本身步骤不是很难,就是画原理图的时候可能会有一点点麻烦,但是之后都挺顺利的,但是!等烧完看串口的时候就是另一个故事了,可能就是一根线或者是电压不对所以就是没显示,或者是显示其他的东西。
参考文献:
(74条消息) 各种SD卡参数及接口_tiandiren111的专栏-CSDN博客
(74条消息) 【嵌入式20】STM32F103完成对SD卡的数据读取详细操作_噗噗的罐子博客-CSDN博客
(74条消息) 使用Altium Designer18绘制stm32最小系统的电路原理图,并在此基础上完成STM32+SD卡 的系统原理图设计_CCChenn mi的博客-CSDN博客