STM32 系列使用知识问题笔记

	STMF103用了这么多年,项目也做过不少,当然也遇到过很多问题,虽然现在使用起来也算得上得心应手,
	但是有些地方还是用起来还是得查查看看,所以就专门开设一篇文章,放一些基本笔记,方便以后查找。
	这里的笔记知识大多都是以前网上查找保存的笔记,后续维护在自己遇到问题的时候会多放些自己踩过的坑。

1、获取定时器时钟频率

uint32_t get_time_clock_freq(TIM_TypeDef *t) {
    uint32_t time_clock_freq = 0;
    RCC_ClocksTypeDef clocks;
    RCC_GetClocksFreq(&clocks);
    if(t == TIM1 || t == TIM8) {
        time_clock_freq = clocks.PCLK2_Frequency;
        if(clocks.HCLK_Frequency/clocks.PCLK2_Frequency > 1) {
            time_clock_freq <<= 1;
        }
    } else {
        time_clock_freq = clocks.PCLK1_Frequency;
        if(clocks.HCLK_Frequency/clocks.PCLK1_Frequency > 1) {
            time_clock_freq <<= 1;
        }
    }
    return time_clock_freq;
}
————————————————
版权声明:本文为CSDN博主「矜辰所致」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42328389/article/details/118212278

2、ADC通道对应关系

在这里插入图片描述

3、中断优先级

在这里插入图片描述

4、ADC采样计算

在这里插入图片描述

5、DMA

DMA用在什么地方合适?形象地说,DMA是MCU内的搬运工,通过DMA把数据从外设和内存之间的自动搬迁,节省软件的开销。

STM32 的DMA有三种模式:内存-外设,外设-内存,内存-内存。

举几个例子:

USART串口发送:没DMA的情况,要发送大量数据,需要每一个字节发送后产生完成中断或轮询旗标,然后软件介入把下一个数据放入TDR寄存器,这样会有大量中断或等待消耗程序的资源,如果采用DMA的话,至需要预先在DMA通道设定要发送的数据的第一字节的内存地址(例如: &buf[0]), 和设定需要发送多少字节,开始发送后,DMA就会像z指针一样完成一节,指针自动递增或减自动移动数据到发送寄存器,直至发送完成会有一次中断通知。中间过程软件完全可以不介入。

ADC采集:多次采样或循环采样,同样地没DMA的话,采样完毕中断,搬移ADC的采样值,出现大量中断,如果是高速采样情况更甚。可以通过DMA采样完成后自动写入你指定的数组地址,一个循环后DMA一个完成中断通知你做后续的事情,例如平均算法之类的。

DAC波形输出:把波形的样本建立一个数组,使用DMA循环发送。

用和不用当然都可以发送。不用DMA发送是需要单片机实时参与,由单片机一个一个地发送数据并进行监控。但是如果用DMA,设置了起始地址,数据大小等参数后,就直接由专门的一个DMA模块进行数据发送,发送过程中单片机无需参与。发送完后会产生中断告知单片机。由此可知用DMA可以节省单片机资源,让单片可以在同一时间里干更多事。

6、I2C通讯(软件I2C)

起始信号:时钟线高电平的时候,数据线由高变低

void i2c_start(void)
{
   sda_high;
   delay_us(5);
   scl_high;
   delay_us(10);
   sda_low;
   delay_us(10);
   scl_low; //使SCL置低,准备发送或者接受数据
   delay_us(10);
}

结束信号:时钟线高电平的时候,数据线由低变高

void i2c_stop(void)
{ 
   sda_low;
   delay_us(5);
   scl_low;
   delay_us(10);
   scl_high;
   delay_us(5);
   sda_high;
   delay_us(10); 
}

ACK:正常的时钟周期,保持低电平,主机和从机都需要响应ACK

void IIC_Ack(void)
{
	MYIIC_CLK_LOW;    //SCL为低,SDA为低,SCL为高,SDA为低,应答低电平有效,SCL为低,产生应答信号
	// MYSDA_OUT;
	MYIIC_DATA_LOW;
	delay_us(10);
	MYIIC_CLK_HIGH;
	delay_us(10);
	MYIIC_CLK_LOW;
	/*注意,加上了下面一句,释放总线,数据才正确*/
	delay_us(10);
	MYIIC_DATA_HIGH;
}

NACK:正常的之中周期,保持高电平,一般在接收数据的最后一个字节,发送NACK,表示接收完成

void IIC_NAck(void)
{
	scl_low;     //SCL为低,SDA为高,SCL为高,SCL为低
	// MYSDA_OUT;
	sda_high;
	delay_us(10);
	scl_high;
	delay_us(10);
	scl_low;
}

在添加I2C设备的时候,读取数据时候,主机需要返回ACK给从机,但是得注意主机返回ACK最后需要释放 SDA线,在以前使用的过程中,遇到过没有释放也可以成功的例子。

但是最近在使用STM32L051添加欧姆龙 D6T-1A-02非接触温度传感器的时候遇到,如果不在返回ACK后释放SDA线控制权,从机无法正常发送数据(因为SDA先被主机拉低了,从机无法拉高):

7、HAL库中的串口操作

使用STMCubeMX生成工程后,会自动设置好NVIC中断优先级,使能了NVIC中断,在usart.c下的`void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)中有:

HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);

但是串口的接收中断,是没有自动使能的,我们需要自己使能,但是如何使能,比如:

/*USART_Enocean_BUF , USART_RX_BUF 是你的接收缓冲区*/
HAL_UART_Receive_IT(&hlpuart1, USART_Enocean_BUF, 1);
HAL_UART_Receive_IT(&huart2, USART_RX_BUF, 1);

如果你需要接收一帧数据,可以开启IDLE中断,初始化后,运行前加上
__HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);
那么还有一句:
__HAL_UART_ENABLE_IT(&huart2,UART_IT_RXNE);
这句话是不是开启了前面的HAL_UART_Receive_IT就不需要用了呢?
实际上测试是这么回事,以前在标准库中使用串口通讯UART_IT_RXNE基本上都必须使能的,那么为什么?

在这里插入图片描述
见文章:RT-Thread 应用篇 — 在STM32L051上使用 RT-Thread (四、无线温湿度传感器 之 串口通讯)
《4.2 串口通讯细节问题》

8、中断操作

屏蔽外部中断
关闭中断
EXTI->IMR &= ~(EXTI_Linex);
打开中断
EXTI->IMR |= EXTI_Linex;

在Hal库中:

void HAL_NVIC_EnableIRQ(IRQn_Type IRQn)
{
  /* Check the parameters */
  assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
  
  /* Enable interrupt */
  NVIC_EnableIRQ(IRQn);
}

/**
  * @brief  Disable a device specific interrupt in the NVIC interrupt controller.
  * @param  IRQn External interrupt number .
  *         This parameter can be an enumerator of IRQn_Type enumeration
  *         (For the complete STM32 Devices IRQ Channels list, please refer to stm32l0xx.h file)  
  * @retval None
  */
void HAL_NVIC_DisableIRQ(IRQn_Type IRQn)
{
    /* Check the parameters */
  assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
  
  /* Disable interrupt */
  NVIC_DisableIRQ(IRQn);
}

举例:

...
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);
...
if(...){
	HAL_NVIC_DisableIRQ(EXTI4_15_IRQn); 
}

9、位操作

对寄存器的操作,使用位操作是效率最高的方式。

置位
int a = 0x123;把a的 bit 7,8位 置位:
int b = a | (1<<7) | (1<<8);

GPIOA -> ODR |=1<<5; //PA5输出 1,其他位不变

清位
int a = 0x123; 把a 的 bit7,8 清0;
int b = (a & ~( 1<<7))&(~ (1<<8));

10、FreeRTOS中断中死机问题

中断中使用printf函数死机问题,本来只是为了测试看一下,实际应用当然是在中断中不能使用printf的,但是以前确实也没有遇到死机问题,这一次在使用FreeRTOS 的时候,中断中只要使用printf就死机,程序无法调度了,具体原因还不知道,只能避免,相关部分截图先放在下面,以后如果知道答案可以来分析一下。

在中断中养成不用打印的好习惯!!!!!切记,测试可以,实际项目不可以!

硬件平台 STM32L051C8T6:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

11、STM32 如何定义变量到FLASH 中

在使用AVR,8051单片机的时候,如果在变量定以前加上 code 关键字,表示 定义的数据要放在 ROM中:

code uint8 EEP_Info[EEP_TYPE_Num][2] = { 
                    					0x02,0x01,
										0x02,0x02,
										0x02,0x03,
										0x02,0x04,
										0x02,0x05
										};

那么对于 STM32 而言呢,需要加关键字 const msp430也是。

const uint8 EEP_Info[EEP_TYPE_Num][2] = { 
                    					0x02,0x01,
										0x02,0x02,
										0x02,0x03,
										0x02,0x04,
										0x02,0x05
										};

12、 关于__attribute__((packed))

在结构体后面的 attribute ((packed)) 的作用就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐,比如:

typedef struct
{
    u8 ID1;
    u8 ID2;
    u8 ID3;
    u8 ID4;
    u8 ID5;
    u8 ID6;
    u32 state;

}__attribute__ ((packed)) BlueID_STRUCT;

不对齐,结构体的长度,就是各个变量长度的和!

当然也可以指定字节对齐(4字节对齐):

typedef struct
{
    u8 ID1;
    u8 ID2;
    u8 ID3;
    u8 ID4;
    u8 ID5;
    u8 ID6;
    u32 state;

}__attribute__ ((aligned(4))) BlueID_STRUCT;

13、 extern 声明结构体

C语言要定义外部文件可使用的结构体和结构体变量。

需要保证 extern 声明的 文件中,有结构体的定义

在这里插入图片描述所以需要改成 在 定义的文件中 声明:
在这里插入图片描述

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

矜辰所致

您们的鼓励是我奋斗的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值