1. 写时钟延迟函数
原理是72MHZ对应72次振动1微秒。
AHB这里是最高频率72MHZ
STK_LOAD寄存器只能存储24位的。
代码如下:
注意这个函数的调用方式,要避免超出2^24的数值,2^16是25535。
PS:如果在工作当中需要写微秒级别的函数可以参考上面的代码(HAL库自动生成代码无法实现微秒),在51芯片当中一个指令1.08微秒无法做到这个精度。
用hal库实现毫秒级延时
(后续: CSDN你M死了 我看了半天一调试,只要超过 1MS 也就是 1000ms)
我看了半天一调试,只要超过 1MS 也就是 大于1000us 就是 大于 递减 72000 次 就无法准确计数
例如我想定时 1ms + 1us delays = 72000 + 72 = 72072
wait = 72000 + startval - delays;
wait = 72000 + 72000 - 72072
wait = 72072
SysTick->VAL 重装载值 是 72000
while(wait < SysTick->VAL);👈这条空转语句执行都不执行了 我草泥马 那些这个if(delays > startval)语句不是脱裤放屁吗??? 你妈死了 浪费我这么多时间!草!!!
void delay_us(uint32_t udelay)
{
uint32_t startval,tickn,delays,wait;
startval = SysTick->VAL; //获取未开始前定时器计数值(已设定的值)
tickn = HAL_GetTick();//获取当前计数器值(运行中)
//sysc = 72000; //SystemCoreClock / (1000U / uwTickFreq);
delays =udelay * 72; //sysc / 1000 * udelay;
if(delays > startval)
{
while(HAL_GetTick() == tickn)
{
}
wait = 72000 + startval - delays;
while(wait < SysTick->VAL)
{
}
}
else
{
wait = startval - delays;
while(wait < SysTick->VAL && HAL_GetTick() == tickn)
{
}
}
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/u010779035/article/details/104102469
// 这是一个简化的实现,帮助你理解
volatile uint32_t uwTick; // 定义在某个地方,'volatile'防止编译器优化
__weak void HAL_IncTick(void)
{
uwTick += uwTickFreq;//uwTickFreq = 1
}
uint32_t HAL_GetTick(void)
{
return uwTick;
}
1. 嵌入式分层思想和代码实践
垂直分层 (Vertical Tiers): 从硬件到功能
- 驱动层 (Dri):
- 核心任务: 直接操作硬件。
- 作用: 封装对芯片、传感器等硬件的具体读写,向上层提供统一的硬件访问接口,屏蔽硬件差异。是连接硬件和软件的桥梁。
- 系统层 (int):
- 核心任务: 提供运行环境。
- 作用: 集成操作系统(如 FreeRTOS),提供任务调度、内存管理和通信机制。它是整个软件运行的基石和调度中心。
- 中间件层 (mid):
- 核心任务: 提供通用软件服务。
- 作用: 实现与具体业务无关的复杂功能,如网络协议栈 (TCP/IP)、文件系统、图形库等。它让应用层可以专注于业务,而无需重新发明轮子。
- 应用层 (APP):
- 核心任务: 实现产品最终功能。
- 作用:产品的灵魂。调用所有下层服务(驱动、系统、中间件)来组合实现设备的核心业务逻辑和用户交互。它定义了产品“是什么”和“做什么”。
横向模块化 (Horizontal Components): 可重用的积木
- 组件/通用模块 (COM):
- 核心任务: 功能封装与复用。
- 作用: 将某个特定功能(如按键处理、日志系统)打包成一个独立的、可配置的“软件积木”。这些组件可以被不同项目、不同层级复用,极大地提高了开发效率和代码质量。
实际代码如下头文件能写的部分:
2. 总体架构和时钟系统
2.1. 总体架构
3个被动单元(无法主动发出信号):
4个主动(驱动)单元(主动发出信号):
其他单元:
2.2. 时钟系统
两个无源的晶振:
HSE:8Mhz
LSE:32.768khz(2^15)
内部两个RC振荡器:
LSI(Low Speed Internal)-40khz
HSI(Hight Speed Internal)-8Mhz
3. HEL库创建项目流程
3.1. pinout & configuration
SYS选择 systick 是24位 向下计数的定时器,Debug选择 Serial Wire
RCC设置 HSE,LSE 选择Crystal/Ceramic Resonator (无源晶振)
GPIO设置
3.2. Clock Configuration
3.3. Project Manager
3.4. HAL库自动生成DRI底层代码原理-看头文件总结:
没事自己去尝试翻一下HAL库生成的代码。
3.5. HAL库常用函数-GPIO相关
这次常用的HAL库函数有:
HAL_GPIO_WritePin();//以set和reset为主
HAL_GPIO_ReadPin();
HAL_Delay();//ms级别
4. 代码附录:
#ifndef __DRI_LED_H__
#define __DRI_LED_H__
#include "stm32f10x.h"
#define __Dri_Led_Led0__ GPIO_ODR_ODR0
#define __Dri_Led_Led1__ GPIO_ODR_ODR1
#define __Dri_Led_Led2__ GPIO_ODR_ODR8
void Dri_Led_Init(void);
void Dri_Led_On(uint16_t led);
void Dri_Led_Off(uint16_t led);
void Dri_Led_AllOn(uint16_t led[],uint8_t len);
void Dri_Led_AllOff(uint16_t led[],uint8_t len);
void Dri_Led_Toggle(uint16_t Led);
#endif /* __DRI_LED_H__ */
#include "Dri_Led.h"
void Dri_Led_Init(void)
{
RCC->APB2ENR |=RCC_APB2ENR_IOPAEN;//advanced peripheral bus 2 enable rigistor
GPIOA->CRL |=(GPIO_CRL_MODE0|GPIO_CRL_MODE1);//start led0 and led1 mode,this is mode is output 50mhz
GPIOA->CRH|=GPIO_CRH_MODE8;//start led2 mode,this is mode is output 50mhz
GPIOA->CRL &=~(GPIO_CRL_CNF0|GPIO_CRL_CNF1);//use general purpose push-pull output in led0 and led1
GPIOA->CRH &=~GPIO_CRH_CNF8;//use general purpose push-pull output in led2
GPIOA->ODR |=(__Dri_Led_Led0__|__Dri_Led_Led1__|__Dri_Led_Led2__);//use define led0,1,2 to high level to prevent led0,1,2 to light,it retain dark at begin.
}
void Dri_Led_On(uint16_t led)//because GPIO_ODR_ODR0 is 16bit,so we use 16bit suit to define.
{
GPIOA->ODR &=~ led;
}
void Dri_Led_Off(uint16_t led)
{
GPIOA->ODR |=led;
}
void Dri_Led_AllOn(uint16_t led[], uint8_t len)
{
for (uint8_t i = 0; i < len; i++)
{
GPIOA->ODR&=~led[i];
}
}
void Dri_Led_AllOff(uint16_t led[], uint8_t len)
{
for (uint8_t i = 0; i < len; i++)
{
GPIOA->ODR|=led[i];
}
}
void Dri_Led_Toggle(uint16_t Led)
{
((GPIOA->IDR&Led)==0)?(GPIOA->ODR|=Led):(GPIOA->ODR&=~Led);
}
#ifndef __DRI_DELAY_H__
#define __DRI_DELAY_H__
#include "stm32f10x.h"
void Dri_Delay_us(uint16_t us);
void Dri_Delay_ms(uint16_t ms);
void Dri_Delay_s(uint16_t s);
#endif /* __DRI_DELAY_H__ */
#include "Dri_Delay.h"
void Dri_Delay_us(uint16_t us)
{
SysTick->LOAD|=us*72;//systemtick*72,because 72mhz corresponding 10^6 is correct for 1us.
SysTick->CTRL|=SysTick_CTRL_ENABLE;
SysTick->CTRL&=~SysTick_CTRL_TICKINT;
SysTick->CTRL&=~SysTick_CTRL_COUNTFLAG;
SysTick->CTRL|=SysTick_CTRL_CLKSOURCE;
while ((SysTick->CTRL&SysTick_CTRL_COUNTFLAG)==0)
{};
}
void Dri_Delay_ms(uint16_t ms)
{
while (ms--)
{
Dri_Delay_us(1000);
}
}
void Dri_Delay_s(uint16_t s)
{
while (s--)
{
Dri_Delay_ms(1000);
}
}
5. 代码TIP-粑粑巴士
6. 英文附录
STK_CTRL 的全称就是 SysTick Control Register
AHB 是 Advanced High-performance Bus 的缩写。翻译成中文是 “高级高性能总线”。
SRAM: Static Random-Access Memory, 静态随机存取存储器, 用作高速内存,存放程序运行时的变量和堆栈。
AHB: Advanced High-performance Bus, 先进高性能总线, 连接CPU、SRAM、Flash等高速系统部件的总线。
APB: Advanced Peripheral Bus, 先进外设总线, 连接UART、I2C、SPI、定时器等低速外设的总线。
内部RC振荡器中的RC : Resistor, 电阻器, 在电路中用于限制电流的流动,并控制电容的充电速度。Capacitor, 电容器, 在电路中用于储存和释放电荷,通过周期性的充放电产生振荡基础。




