命名规范
STM32F051K8U6
ST - 公司
M - micro eletronics
32 - 32位处理器 STM8
F - 基础版 L - 低功耗 G - 电源
051 - 入门级别 103 - 主流级别 407 - 高性能
K - 32个管脚
8 - 64K
U - UQFN 封装类型
6 - 工作温度范围
STM32
和ARM
的关系?
STM32
的CPU
是采用的ARM-CortexM0
架构的
ARM
处理器命名规范
ARM7\9\11
Cortex - A : 开放式操作系统 手机 智能电视
Cortex - R : 实时系统 汽车电子
Cortex - M : 低成本的优化解决方案
实时操作系统:一般用于单片机
分时操作系统:通过时间片轮转进行调度工作 Linux典型的分时操作系统
最大区别就是响应速度。
处理器和架构?
三星S5P6818 ARM-cortexA53 v8
麒麟990 4ARM-cortexA55+4ARM-cortexA76 v8
Cortex-M0
主要功耗和性能的平衡
Cortex-M0
微处理器主要包括处理器内核、嵌套向量中断控制器(NVIC
)、调试子系统、内部总线系统构成,通过高性能总线(AHB-LITE
)与外部进行通信。
Thumb
状态:正常运行时处理器的状态R0-R12
13个通用寄存器R13
(SP
栈指针):Cortex-M0
在不同物理位置上存在两个栈指针,主栈指针 MSP
,进程栈指针PSP
。在处理模式下,只能使用主堆栈,在线程模式下,可以使用主堆栈也可以使用进程堆栈,这主要是由 CONTROL
寄存器控制完成。系统上电的默认栈指针是MSP
。R14
(LR
链接寄存器):程序跳转时保存当前正在执行的下一条指令地址。R15
(PC
程序计数器):存储下一条将要执行的指令的地址。xPSR
:组合程序状态寄存器,该寄存器由三个程序状态寄存器组成PSR
(APSR
):包含前一条指令执行后的条件标志PSR
(IPSR
):包含当前ISR
的异常编号PSR
(EPSR
):包含Thumb
状态位Cortex-M0
处理器最多支持 32 个外部中断(通常称为 IRQ)和一个不可屏蔽中断(NMI),
另外 Cortex-M0
还支持许多系统异常(Reset、HardFault、SVCall、PendSV、SysTick
)
ARM
指令集
32位精简指令集;
指令长度固定;
降低编码数量产生的耗费,减轻解码和流水线的负担;
Thumb
指令集
Thumb
指令集是ARM
指令集的一个子集;
指令宽度16位;
与32位指令集相比,大大节省了系统的存储空间;
Thumb
指令集不完整,所以必须配合ARM
指令集一同使用。
0x28000000
MODER
0x00OTYPER
0x04#define GPIOA_BASE ((usigned int)0x28000000)
#define GPIOA_OTYPER *(unisgned int *)(GPIOA_BASE+0x04)
typedef struct
{
__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
__IO uint32_t BSRR; /*!< GPIO port bit set/reset register, Address offset: 0x1A */
__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
__IO uint32_t AFR[2]; /*!< GPIO alternate function low register, Address offset: 0x20-0x24 */
__IO uint32_t BRR; /*!< GPIO bit reset register, Address offset: 0x28 */
} GPIO_TypeDef;
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
GPIOA->OTYPER = 0X20;
GPIOA->OTYPER
的第6位置1,第7位置0。 GPIOA->OTYPER = GPIOA->OTYPER & ~(0x3 << 6) | (1<<6)
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOA_BASE (AHB2PERIPH_BASE + 0x00000000UL)
#define AHB2PERIPH_BASE (PERIPH_BASE + 0x08000000UL)
#define PERIPH_BASE 0x40000000UL /*!< Peripheral base address in the alias region */
Stack_Size EQU 0x400 //初始化栈空间为1K
AREA STACK, NOINIT, READWRITE, ALIGN=3 //定义一个段STACK,未初始化,可读可写,ALIGN=3 以2^3 = 8字节对齐
Stack_Mem SPACE Stack_Size
__initial_sp
Heap_Size EQU 0x200 //初始化堆空间为512字节
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
D10
绿灯 - LED4
- 核心板PB0
PB0
这个管脚输出低电平即可GPIOB
的时钟RCCAHBENR
的第18位置1RCC->AHBER |= 1<<18;
PB0
为输出模式GPIOBMODER
的第0位置1,第1位清零。GPIOB->MODER &= ~(0x3);
GPIOB->MODER |= 0x1;
PB0
为推挽输出GPIOBOTYPER
的第0位清零;GPIOB-> OTYPER &= ~0x1
GPIOBODR
的第0位清零 GPIOB->ODR &= ~0x1
三极管(流控)
放大状态:发射结(BE)正偏,集电结(BC)反偏。
饱和状态:发射结正偏,集电结正偏。
截止状态:发射结反偏,集电结反偏。
推挽输出:具备输出高低电平的能力。
开漏输出:具备输出低电平的能力,可通过外加上拉电阻输出高电平。
浮空输入 :IO -> 施密特触发器 -> 输入寄存器 -> 读
模拟输入 : IO -> 输入寄存器 -> 读
上拉输入 : IO -> 上拉电阻 -> 施密特触发器 -> 输入寄存器 -> 读
下拉输入 :IO -> 下拉电阻 -> 施密特触发器 -> 输入寄存器 -> 读
GPIOx_MODER
模式寄存器GPIOx_OTYPER
输出类型寄存器GPIOx_OSPEEDR
输出速度寄存器GPIOx_PUPDR
上拉下拉寄存器GPIOx_IDR
输入数据寄存器GPIOx_ODR
输出数据寄存器GPIOx_BSRR
GPIOx_AFRH
复用功能高位寄存器GPIOx_AFRL
复用功能低位寄存器开启GPIOB的时钟
RCC_AHBENR
位 18 IOPBEN: GPIOB 时钟使能
由软件置 1 或清 0.
0: GPIOB 时钟关闭
1: GPIOB 时钟开启
RCC->AHBENR |= 1<<18
选择输出模式
GPIOB_MODER 010101
MODERy[1:0]: 端口 x 配置位 (y = 0…15)
这些位可由软件写来配置 I/O 口模式。
00: 输入模式 ( 复位状态 )
01: 通用输出模式
10: 复用功能模式
11: 模拟模式
GPIOB->MODER |= (1<<0)|(1<<2)|(1<<4)
选择输出类型
GPIOx_OTYPER
OTy[1:0]: 端口 x 的配置位 (y = 0…15)
这些位可由软件写来配置 I/O 口的输出类型。
0: 推挽输出 ( 复位状态 )
1: 开漏输出
GPIOB->OTYPER = 0x0;
配置输出数据
GPIOB_BSRR 端口置位 / 复位寄存器
位 31:16 BRy: 端口 x 复位位 y(y = 0…15)
这些位只写。读这些位时返回 0x0000 数值。
0: 对相应的 ODRx 位无影响
1: 复位相应的 ODRx 位
GPIOB -> BSRR = (0x7 << 16);
//LED灯初始化
void LED_Init()
{
RCC->AHBENR |= 1<<18; //使能GPIOB的时钟
GPIOB->MODER |= (1<<0)|(1<<2)|(1<<4); //配置PB0为输出模式
GPIOB->OTYPER = 0x0; //配置为推挽输出
}
void main()
{
while (1)
{
//实现三个LED灯闪烁
GPIOB -> BSRR = (0x7 << 16);//复位PB0 PB1 PB2输出低电平
HAL_Delay(500);
GPIOB -> BSRR = 0x7; //置位PB0 PB1 PB2 输出高电平
HAL_Delay(500);
}
}
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
GPIO_TypeDef* GPIOx 端口 A...F
uint16_t GPIO_Pin 引脚编号 0 - 15
GPIO_PinState PinState
GPIO_PIN_RESET: 清0 低电平
GPIO_PIN_SET: 置1 高电平
返回值:空
void MX_GPIO_Init(void) //LED初始化函数
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE(); //使能GPIOB的时钟
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2, GPIO_PIN_RESET);
//配置PB0 PB1 PB2 初始状态为输出低电平
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //配置输出模式为推挽输出
GPIO_InitStruct.Pull = GPIO_NOPULL; //无上拉下拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; //输出速度为低速
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); //使能GPIOB组
}
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0|GPIO_PIN_2,GPIO_PIN_SET);
HAL_Delay(200);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0|GPIO_PIN_1,GPIO_PIN_SET);
HAL_Delay(200);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1|GPIO_PIN_2,GPIO_PIN_SET);
HAL_Delay(200);
D3&KEY
输出D3&KEY
这个管脚读到高电平PA8
管脚连接D3&KEY
PA8
管脚输入的信号即可判断按键是否被按下PA8
管脚的值HAL_GPIO_ReadPin
GPIO_PinState HAL_GPIO_ReadPin (GPIO_TypeDef * GPIOx,uint16_t GPIO_Pin)
功能:读管脚的电平值
参数:GPIOx
端口号
GPIO_Pin
管脚编号
返回值:GPIO_PinState
管脚实际的电平值
if(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin) == 1)
{
HAL_GPIO_WritePin(LED4_GPIO_Port,LED4_Pin,0);
}else
{
HAL_GPIO_WritePin(LED4_GPIO_Port,LED4_Pin,1);
}
HAL_Delay(100);
void HAL_GPIO_TogglePin (GPIO_TypeDef * GPIOx, uint16_tGPIO_Pin)
功能:电平翻转
参数:GPIOx
端口号
GPIO_Pin
管脚编号
返回值:空
//按键按一次 LED切换一次状态
if(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin) == 1)
{
while(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin) == 1);
//抬手监测
HAL_GPIO_TogglePin(LED4_GPIO_Port,LED4_Pin);
}
根据时钟源可以区分为:
通过通信方式区分为:
根据传输方向区分为:
单工:只能作为接收设备或者发送设备,要么收要么发。 广播、收音机
半双工:可以接收也可以发送,但是同一时间只能发送或接收。对讲机
全双工:同一时间既可作为发送端又可作为接收端。手机
UART
– 异步通信 串行 全双工
USART
– 同步通信
(5v)TTL
电平 : 逻辑1 :2.4v ~ 5v
逻辑0: 0 ~ 0.5v
EIA电平(RS232): 逻辑1 : -3v ~ -15v 逻辑0:+3v ~ +15v 15m
RS485 :双绞线 差分信号 1300m
逻辑1 : 2v ~ 6v 逻辑0:-2v ~ -6v
单片机 — 串口线 — 电脑
CH340
USB转串口芯片
起始位(1位):低电平
数据位(8位):
校验位(1位):奇偶校验
停止位(1位):高电平
奇校验:数据位中1的个数+校验位上1的个数为奇数
偶校验:数据位中1的个数+校验位上1的个数为偶数
例如:
发送01010101采用奇校验,校验位应该为1
数据接收过程 : RX -> 接收移位寄存器 -> 接收数据寄存器 -> CPU or DMA
数据发送过程 : CPU or DMA -> 发送数据寄存器 -> 发送移位寄存器 —> TX
配置寄存器:
控制寄存器 USART_CR1 CR2
波特率寄存器 USART_BRR
发送数据寄存器:
中断和状态寄存器USART_ISR
接收数据寄存器 USART_RDR
发送数据寄存器USART_TDR
PA9
– USART1_TX
PA10
– USART1_RX
CubeMX
USART1
- 异步通信Asynchronous
USART1
参数115200
8位
NONE
1位
void My_Putchar(uint8_t ch)
{
while(!(USART1->ISR & (1<<7)));
USART1->TDR = ch;
}
完成串口接收函数
实现大小写转换
例如:通过串口给单片机发送大写字母A,单片机返回小写字母a。
先实现串口接收函数:
uint8_t My_Getchar(void)
{
uint8_t ch;
while(!(USART1->ISR & (1<<5))); //等待接收寄存器非空
ch = USART1->RDR;
return ch;
}
在main函数里实现:
while(1){
ch = My_Getchar();
if(ch>='A'&&ch<='Z')
{
My_Putchar(ch + 32);
}else if(ch>='a'&&ch<='z')
{
My_Putchar(ch - 32);
}else
{
My_Putchar('?');
}
}
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
UART_HandleTypeDef *huart
: 句柄 (注意取地址)uint8_t *pData
: 发送的字符数组首地址uint16_t Size
: 发送数据长度uint32_t Timeout
: 超时时间(规定时间内没完成发送返回HAL_TIMEOUT
HAL_UART_Transmit(&huart1, "hello test\n", strlen("hello test\n"), 100);
HAL库版本接收数据:
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
通过HAL库函数实现串口收发:
uint8_t str[32] = {0};
while(1){
HAL_UART_Receive(&huart1, str,sizeof(str), 100);
HAL_UART_Transmit(&huart1, str, strlen(str), 100); //用strlen记得添加string.h文件
memset(str,0,sizeof(str));
}
a想要发送一个不定长度的到串口
将printf打印的内容输出到串口中,因为printf使用标准库fputc
那么我们将fputc
重写即可
添加stdio.h
头文件,编译后查找fputc
函数 将函数原型找出来
extern _ARMABI int fputc(int /*c*/, FILE * /*stream*/) __attribute__((__nonnull__(2)));
重写fputc函数:
int fputc(int ch, FILE *file)
{
while(!((huart1.Instance->ISR) & (1<<7)));
huart1.Instance->TDR = ch;
return ch;
}
007A1200
02DC6C00
在main.c里测试printf:
printf(“hello world\n”);
重写fgetc
函数
extern _ARMABI int fgetc(FILE * /*stream*/) __attribute__((__nonnull__(1)));
int fgetc(FILE * file)
{
int ch;
while(!((huart1.Instance->ISR) & (1<<5)));
ch=huart1.Instance->RDR;
return ch;
}
在main
函数里通过scanf和printf实现输入输出:
scanf("%s",buf);
printf("%s",buf);
注意: 在串口工具里发送字符串时记得添加/r/n结束标志 (可参考群里图片设置自动发送附加位)
概念:当处理器在正常执行程序时,突然有外部/内部中断事件发生,
此时需要暂停当前正在执行的程序,并进行备份,转而去处理中断事件,
处理完成后,返回当时程序执行位置继续执行。
举例
老师正在讲课 (正常执行的程序)
老徐叫我去开会 (外部中断信号)
暂停讲课保存课堂笔记 (压栈保护现场)
跳转到中断处理程序 (根据异常向量表进行跳转)
开会 (执行中断处理程序)
会后回来继续上课 (出栈恢复现场)
意义:提高突发事件的处理效率
NVIC 嵌套向量中断控制器
管理中断
每一个外部中断进来都可能被执行或禁止,并可以设置为挂起状态或清除状态。
挂起:当处理器正在处理高优先级事件时,低优先级中断事件会先被设置为挂起状态。
清除:当处理完中断处理程序时,可将该中断事件设置为清除状态。
支持中断或异常的向量化处理
当异常或中断发生时,给定PC一个特定的地址,对应各个中断或异常处理程序的执行地址,这个按照优先级排列组成的地址列表称为中断向量表。
异常:来自于处理器内部的异常事件
中断:来自于处理器外部的中断事件
支持中断嵌套
按键按下,触发中断控制串口打印“interrupt”
查看芯片原理图
按键 – PA8
使能UART1为异步通信模式 – PA9 PA10
在CubeMX中进行配置
打开工程
启动文件中找到对应的中断向量
DCD EXTI0_1_IRQHandler ; EXTI Line 0 and 1
DCD EXTI2_3_IRQHandler ; EXTI Line 2 and 3
DCD EXTI4_15_IRQHandler ; EXTI Line 4 to 15
找到中断处理函数
void EXTI4_15_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_8);
}
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); //清楚中断标志
HAL_GPIO_EXTI_Callback(GPIO_Pin); //处理中断回调函数
}
}
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) //__weak弱化符 可重写该函数
{
UNUSED(GPIO_Pin);
}
在gpio.c里重写中断回调函数:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_8) //判断是否为EXTI8中断事件
{
printf("interrupt!"); //打印“interrupt”
}
}
串口发送完成中断 串口发送“hello”完成之后触发中断事件,在中断中发送“world”。
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
}
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
UART_EndTransmit_IT(huart);
static void UART_EndTransmit_IT(UART_HandleTypeDef *huart)
{
ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_TCIE);
huart->gState = HAL_UART_STATE_READY;
huart->TxISR = NULL;
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
huart->TxCpltCallback(huart);
#else
HAL_UART_TxCpltCallback(huart);
#endif
}
__weak void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
UNUSED(huart);
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_Transmit(&huart1,"world",sizeof("world"),100);
}
HAL_UART_Transmit_IT(&huart1,"hello",sizeof("hello"));
串口接收完成中断
//重写接收完成中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_Transmit(&huart1,"Recive 4 char",sizeof("Recive 4 char"),100);
}
//main.c中触发接收中断
while (1)
{
HAL_UART_Receive_IT(&huart1,str,4); //接收4个字符 触发一次中断
HAL_Delay(1000);
printf("%s",str);
memset(str,0,sizeof(str));
}
while(1)
{
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_8))
{
HAL_Delay(100);
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_8))
{
HAL_ADC_Start(&hadc);
HAL_ADC_PollForConversion(&hadc,100);
value = HAL_ADC_GetValue(&hadc);
HAL_ADC_Stop(&hadc);
printf("key:%d",value);
}
}
void SysTick_Handler(void)
{
HAL_IncTick();
}
__weak void HAL_IncTick(void)
{
uwTick += uwTickFreq;
//uwTick +=1 ; --> uwTick++;
}
__IO uint32_t uwTick; // __IO防止编译器优化 uwTick是个全局变量 初始值是0
HAL_TickFreqTypeDef uwTickFreq = HAL_TICK_FREQ_DEFAULT; //枚举类型
HAL_TICK_FREQ_1KHZ = 1U //就是1
HAL_TICK_FREQ_DEFAULT = HAL_TICK_FREQ_1KHZ
__weak void HAL_Delay(uint32_t Delay) //想要延时的毫秒数
{
uint32_t tickstart = HAL_GetTick();
//tickstart一上来是1
uint32_t wait = Delay; //想要延时的值放到wait里
if (wait < HAL_MAX_DELAY) //判断延时时间是否合法
{
//wait += (uint32_t)(uwTickFreq);
//wait +=1; wait ++;
}
while((HAL_GetTick() - tickstart) <= 10*wait)
{
1-1 < 11
2-1 < 11 1-11 --- 10ms
12 - 1= 11
}
}
__weak uint32_t HAL_GetTick(void)
{
return uwTick; //返回的是不断自增的uwTick值
}
上电之后还是8M 一次过后会改变成我们设置的值
/* Configure the source of time base considering new system clocks settings*/
HAL_InitTick (TICK_INT_PRIORITY);
输入捕获和输出比较
1)输入捕获 :用来获取外部事件的
2)输出比较: 定时器从0开始到CCR的值输出低电平,从CCR到ARR的值输出高电平,循环此过程
CCRX:占空比 ARR:周期
PWM:脉冲宽度调制
寄存器
TIMx_CNT 计数器当前的值
TIMx_ARR 自动重装值
TIMx_CCRx 捕获/比较寄存器
void TIM2_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim2);
}
/* TIM Update event */ 定时器数值更新
if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET)
{
if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET)
{
__HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
HAL_TIM_PeriodElapsedCallback(htim);
}
}
设计思想:
设计一个定时器 (软件层次 结构体:开始时间 想要延时的时间)
函数: 设定定时时间的函数 比较定时时间是否达到
CubeMX
新建一个工程 48M 开两个LED
新建文件
file -new softtimer.c --> core/src
file -new softtimer.h --> core/inc
在Application user上右键选择Add existing file将.c文件添加进来(.h不需要这个操作)
softtimer.h
里
#ifndef __SOFTTIMER_H__
#define __SOFTTIMER_H__
#include "stm32f0xx.h"
—>是在左边Driver/CMSIS
的文件夹下的system_stm32f0xx.c
下找到的头文件
#endif
softtimer.c
里
setTimer compareTimer
两个函数
main.c
文件 测试功能
ADC逐次逼近形的模拟-数字转化器(采样 量化 编码)
*模拟信号和数字信号的区别?是否连续
*dht11-温湿度传感器-直接出数字信号
ADC特性
量程:能测量的电压的范围
分辨率: ADC的分辨率通常以二进制数表示,位数越多分辨率越高,转化时间越长
转化时间:从转化开始到获得稳定的数字信号的时间
19个通道:16个外部(对应16个引脚),3个内部(芯片的温度 定时器的信息 内部参考电压)
ADC的结果以左对齐或者右对齐的方式存在16位的寄存器当中
ADC最高的频率14M(时钟树查看)
转化方式
单通道单单次转化
单通道连续转化
多通道扫描单次转化
多通道扫描连续转化
间隔转化
存在AD的中断和状态寄存器ADC_ISR
EOC:通道转化结束
EOS:序列转化结束
查看电路图
ADC_KEY - PA0 (GPIO引脚复用映射) - AD_IN0
D3&KEY - PA8 - input
clock pre 时钟分频
resolution 精度
Data Ali 对齐方式 - 左右
scan 扫描方式 - 前后
continue 连续转化
discontinue 间隔
DMA 是否以DMA方式开启AD
End of单通道转化结束的标志
Sampling time 采样时间
编程步骤
void ADC1_COMP_IRQHandler(void)
{
HAL_ADC_IRQHandler(&hadc);
}
/* Note: into callback, to determine if conversion has been triggered */
/* from EOC or EOS, possibility to use: */
/* " if( __HAL_ADC_GET_FLAG(&hadc, ADC_FLAG_EOS)) " */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
hadc->ConvCpltCallback(hadc);
#else
HAL_ADC_ConvCpltCallback(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
中断回调函数
__weak void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
}
void DMA1_Channel1_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_adc);
}
/* Transfer Complete Interrupt management*/
if(hdma->XferCpltCallback != NULL)
{
/* Transfer complete callback */
hdma->XferCpltCallback(hdma);
}
void (* XferCpltCallback)(struct __DMA_HandleTypeDef * hdma);
/* Set the DMA transfer complete callback */
hadc->DMA_Handle->XferCpltCallback = ADC_DMAConvCplt;
static void ADC_DMAConvCplt(DMA_HandleTypeDef *hdma)
{
/* Conversion complete callback */
HAL_ADC_ConvCpltCallback(hadc);
}
重写的回调函数
__weak void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
}
int fputc(int ch,FILE *file)
{
while (!(USART1->ISR & 1<<7));
USART1->TDR = ch;
return ch;
}