打印
[其他ST产品]

STM32 定时器 定时时间的计算

[复制链接]
661|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
泡椒风爪|  楼主 | 2022-3-31 15:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

假设 系统时钟是72Mhz,TIM1 是由PCLK2 (72MHz)得到,TIM2-7是由 PCLK1 得到

关键是设定 时钟预分频数,自动重装载寄存器周期的值

/*每1秒发生一次更新事件(进入中断服务程序)。RCC_Configuration()的SystemInit()的

RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2表明TIM3CLK为72MHz。因此,每次进入中

断服务程序间隔时间为

((1+TIM_Prescaler )/72M)*(1+TIM_Period )=((1+7199)/72M)*(1+9999)=1秒 */



使用特权

评论回复
沙发
泡椒风爪|  楼主 | 2022-3-31 15:40 | 只看该作者
定时器的基本设置

   1、   TIM_TimeBaseStructure.TIM_Prescaler = 7199;//时钟预分频数   例如 :时

钟频率=72/(时钟预分频+1)

使用特权

评论回复
板凳
泡椒风爪|  楼主 | 2022-3-31 15:43 | 只看该作者
2、TIM_TimeBaseStructure.TIM_Period = 9999; // 自动重装载寄存器周期的值(定时

时间)     累计 0xFFFF个频率后产生个更新或者中断(也是说定时时间到)

使用特权

评论回复
地板
泡椒风爪|  楼主 | 2022-3-31 15:43 | 只看该作者
3、  TIM_TimeBaseStructure.TIM_CounterMode =  TIM1_CounterMode_Up; //定时器

模式  向上计数

使用特权

评论回复
5
泡椒风爪|  楼主 | 2022-3-31 15:49 | 只看该作者
4、 TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; //时间分割值

使用特权

评论回复
6
泡椒风爪|  楼主 | 2022-3-31 15:51 | 只看该作者
  5、 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);//初始化定时器2

使用特权

评论回复
7
泡椒风爪|  楼主 | 2022-3-31 15:52 | 只看该作者
6、 TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);  //打开中断   溢出中断  

使用特权

评论回复
8
泡椒风爪|  楼主 | 2022-3-31 15:53 | 只看该作者
7、 TIM_Cmd(TIM2, ENABLE);//打开定时器

使用特权

评论回复
9
泡椒风爪|  楼主 | 2022-3-31 15:54 | 只看该作者
或者:

TIM_TimeBaseStructure.TIM_Prescaler = 35999;//分频35999      72M/

(35999+1)/2=1Hz  1秒中断溢出一次

TIM_TimeBaseStructure.TIM_Period = 2000; //计数值2000

((1+TIM_Prescaler )/72M)*(1+TIM_Period )=((1+35999)/72M)*(1+2000)=1秒 */

使用特权

评论回复
10
为你转身| | 2022-3-31 16:15 | 只看该作者
这里有两种写法直接操作寄存器与用库函数,相对来说直接操作寄存器应该更直观一些。

使用特权

评论回复
11
为你转身| | 2022-3-31 16:17 | 只看该作者
调试总会遇到这样那样的小问题 和朋友一起进步总会更快 希望对别人能有点帮助节省些时间

万利的板子 板载的M25P80 PDF写的这一型号有 25MHZ 和50MHZ两种 注意初始化SPI的设置 BAUD至少就要PCLK/2 = 36Mhz

即使配置为主模式发送 时钟也不是连产生的 接收的时候同样需要发送无用字节以维持数据时钟

STM32 的 NSS脚需要配置为软件模式(可以通过寄存器控制NSS高低) 硬件模式下 NSS引脚必须+ 正的逻辑电平 才能将SPE MSTR位时能配置SPI为主模式

先写了一遍 然后借鉴一个sst25vf08的应用笔记又写了一遍 看这个笔记省了不少时间 很感谢

同一地址单元 重新写入需先擦除 否者二次写入后读出无效

其他按照时序走就可以了

使用特权

评论回复
12
为你转身| | 2022-3-31 16:18 | 只看该作者
程序如下:

#define WREN 0x06
#define WRDI 0x04
#define RDSR 0x05
#define WRSR 0x01
#define READ 0x03
#define FAST_READ 0x06
#define PAGE_PROG 0x02
#define SECTOR_ERASER 0xd8
#define BULK_ERASER 0xc7
#define DEEP_SLEEP 0xb9
#define RES 0xab

#define M25P80_SELECT() GPIOB->BRR |= GPIO_Pin_2
#define M25P80_DESELECT() GPIOB->BSRR |= GPIO_Pin_2

u8 SPI_SeRe_Byte(u8 data);
void M25p80_Cmd1b(u8 cmd);
u8 M25p80_Cmd1b_R1b(u8 cmd);
void M25p80_Cmd1b_S1b(u8 cmd , u8 data);
void M25p80_WP_En(void);
void M25p80_Write_En(void);
u8 M25p80_Busy(void);
u8 M25p80_Read_1Byte(u32 addr );
void M25p80_Read_Bytes(u32 addr , u8* re_buf_p , u16 no);
void M25p80_Write_1Byte(u32 addr , u8 data);
void M25p80_Write_Bytes(u32 addr , u8* wr_buf_p , u16 no);
void M25p80_Section_Erase(u32 addr);
void M25p80_Bulk_Erase(void);

/********************************************************************************************************************
* op-code for M25P80 SPI EEROM
* 8Mbit = 1,048,576 bytes = 16 sectors (512 Kbits, 65536 bytes each) = 4096 pages (256 bytes each)
* 1sector = 256 page
* address range 00000 ~ fffffh
*********************************************************************************************************************/

u8 SPI_SeRe_Byte(u8 data)
{
u8 re_data;
while(! (SPI1->SR & 0x0002) );/*TXE?*/
SPI1->DR = data;
while(! (SPI1->SR & 0x0001) );/*RXNE?*/
re_data = SPI1->DR;
return re_data;

}

/************************************************************************************************************
*函数名称:M25p80_cmd1b_r1b/M25p80_Cmd1b_S1b CMD命令发送 返回1BYTE/命令发送跟送1BYTE
************************************************************************************************************/
void M25p80_Cmd1b(u8 cmd)
{
M25P80_SELECT();
SPI_SeRe_Byte(cmd);
M25P80_DESELECT();
}

u8 M25p80_Cmd1b_R1b(u8 cmd)
{
u8 data;
M25P80_SELECT();
SPI_SeRe_Byte(cmd);
data = SPI_SeRe_Byte(0xff);
M25P80_DESELECT();
return data;
}

void M25p80_Cmd1b_S1b(u8 cmd , u8 data)
{
M25P80_SELECT();
SPI_SeRe_Byte(cmd);
SPI_SeRe_Byte(data);
M25P80_DESELECT();
}

/****************************************************************************************************************/


/************************************************************************************************************
*函数名称:M25p80_WP_En/M25p80_Write_En M25p80写保护使能/写使能 status寄存器修改
************************************************************************************************************/
void M25p80_WP_En(void)
{
u8 sta;
sta = M25p80_Cmd1b_R1b(RDSR) | 0x1c;
M25p80_Cmd1b_S1b(WRSR, sta);
M25p80_Cmd1b(WRDI);
}

void M25p80_Write_En(void)
{
u8 sta;
sta = M25p80_Cmd1b_R1b(RDSR) & (~0x1c);
M25p80_Cmd1b_S1b(WRSR, sta);
M25p80_Cmd1b(WREN);
}
/****************************************************************************************************************/


u8 M25p80_Busy(void)
{
u8 sta;
sta = M25p80_Cmd1b_R1b(RDSR);
return (sta & 0x01);
}

u8 M25p80_Read_1Byte(u32 addr )
{
u8 ad[3] , data;
ad[0] = (addr & 0x00ff0000) >> 16;
ad[1] = (addr & 0x0000ff00) >> 8;
ad[2] = (addr & 0x000000ff);

M25P80_SELECT();
SPI_SeRe_Byte(READ);
SPI_SeRe_Byte(ad[0]);
SPI_SeRe_Byte(ad[1]);
SPI_SeRe_Byte(ad[2]);
data = SPI_SeRe_Byte(0xff);
M25P80_DESELECT();
return data;
}


void M25p80_Read_Bytes(u32 addr , u8* re_buf_p , u16 no)
{
u8 ad[3] ;
ad[0] = (addr & 0x00ff0000) >> 16;
ad[1] = (addr & 0x0000ff00) >> 8;
ad[2] = (addr & 0x000000ff);

M25P80_SELECT();
SPI_SeRe_Byte(READ);
SPI_SeRe_Byte(ad[0]);
SPI_SeRe_Byte(ad[1]);
SPI_SeRe_Byte(ad[2]);
for(; no > 0; no--)
*re_buf_p++ = SPI_SeRe_Byte(0xff);
M25P80_DESELECT();
}


/****************************************************************************************************************/

void M25p80_Write_1Byte(u32 addr , u8 data)
{
u8 ad[3] ;
ad[0] = (addr & 0x00ff0000) >> 16;
ad[1] = (addr & 0x0000ff00) >> 8;
ad[2] = (addr & 0x000000ff);


M25p80_Write_En();
M25P80_SELECT();
SPI_SeRe_Byte(PAGE_PROG);
SPI_SeRe_Byte(ad[0]);
SPI_SeRe_Byte(ad[1]);
SPI_SeRe_Byte(ad[2]);
SPI_SeRe_Byte(data);
M25P80_DESELECT();
M25p80_WP_En();
while(M25p80_Busy());
}


void M25p80_Write_Bytes(u32 addr , u8* wr_buf_p , u16 no)
{
/*
u8 ad[3] ;
ad[0] = (addr & 0x00ff0000) >> 16;
ad[1] = (addr & 0x0000ff00) >> 8;
ad[2] = (addr & 0x000000ff);

if( no < 255 -ad[2] ) return 0 ;//PP写操作过本页地址从本页首地址循环写
M25p80_Cmd1b(WREN);
M25P80_SELECT();
SPI_SeRe_Byte(PAGE_PROG);
SPI_SeRe_Byte(ad[0]);
SPI_SeRe_Byte(ad[1]);
SPI_SeRe_Byte(ad[2]);
for(; no > 0; no--)
*wr_buf_p++ = SPI_SeRe_Byte(0xff);
M25P80_DESELECT();
M25p80_Cmd1b(WRDI);
return 1;
*/
for(; no > 0; no--)
{
M25p80_Write_1Byte(addr , *wr_buf_p);
addr++;wr_buf_p++;
}
M25p80_WP_En();
}

/****************************************************************************************************************/

void M25p80_Section_Erase(u32 addr)
{
u8 ad[3] ;
ad[0] = (addr & 0x00ff0000) >> 16;
ad[1] = (addr & 0x0000ff00) >> 8;
ad[2] = (addr & 0x000000ff);

M25p80_Write_En();

M25P80_SELECT();
SPI_SeRe_Byte(SECTOR_ERASER);
SPI_SeRe_Byte(ad[0]);
SPI_SeRe_Byte(ad[1]);
SPI_SeRe_Byte(ad[2]);
M25P80_DESELECT();
while(M25p80_Busy());
M25p80_WP_En();
}

void M25p80_Bulk_Erase(void)
{
M25p80_Write_En();

M25p80_Cmd1b(BULK_ERASER);
while(M25p80_Busy());
M25p80_WP_En();
}

使用特权

评论回复
13
为你转身| | 2022-3-31 16:21 | 只看该作者
这里的多字节写函数void M25p80_Write_Bytes(u32 addr , u8* wr_buf_p , u16 no) 调用了单字节写函数 实际上还是一个一个写 主要因为用页写操作的话 当数据到达页底会返回本页从头开始写 会破坏数据 而且没有字节写操作码感觉比sst25vf08麻烦很多。

使用特权

评论回复
14
为你转身| | 2022-3-31 16:24 | 只看该作者
关于STM32 SPI NSS问题的探讨。
对于STM32的SPI ,Reference Manual中是给出的schematic如下:
按照标准的SPI协议,当SPI被配置为主机模式后,通过SPI对从设备进行操作时,其NSS应该自动置低,从而选中(使能)从设备;一旦不对从设备进行操作,NSS立刻置为高。
但是,我在实际调试过程中却发现:STM32 SPI NSS无法自动实现跳变。 一旦SPI初始化完成并使能SPI,NSS立刻置低,然后保持不变
这个问题一直无法解决,直到我在ST官方论坛上看到国外有些技术人员也在讨论这个问题,他们得出的结论是:STM32 SPI NSS无法自动跳变
From UK (United Kingdom)

Messages : 19

OFF-Line

I've just hit this NSS problem.

What is good:

That the discussion is here on the forum to stop me spending hours trying to work out what I have done wrong. Thanks guys!

What is not good:

That NSS doesn't behave as expected.

What I expected to happen:

I'm expecting to see on my scope what I see in Figure 208 of RM008 Reference Manual, i.e. NSS goes high after the transfer.

Why a working NSS would be very helpful:

I'm using the SPI (with DMA) to clock data into shift registers. If NSS went high after the transfer (as indicated by Figure 208), I could use that edge as the strobe to latch the data across into the shift register outputs. Everything would be done by the peripheral. Fire and forget. As it is with the broken NSS, I have to generate an interrupt and use that to strobe the gpio output (I hate controlling gpio from within interrupt routines).

Any update as to when this will be fixed?

ST官方技术人员也证实:STM32 SPI NSS是不会自动置位和复位的。按照官方说法,ST已经将其列入了改进计划。

使用特权

评论回复
15
为你转身| | 2022-3-31 16:27 | 只看该作者
对于这个问题,可以采用下面的方法解决:



在SPI初始化时,采用NSS soft模式,然后使能NSS输出功能。从而将NSS当做GPIO使用,通过软件set和reset来实现NSS的置位和复位。



具体代码如下:



/* SPI1 configuration ------------------------------------------------------*/

SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;

SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;

SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;

SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//SPI_FirstBit_MSB;

SPI_InitStructure.SPI_CRCPolynomial = 7;

SPI_Init(SPI1, &SPI_InitStructure);



/*Enable SPI1.NSS as a GPIO*/

SPI_SSOutputCmd(SPI1, ENABLE);



/*Configure PA.4(NSS)--------------------------------------------*/

GPIO_InitStructure.GPIO_Pin =GPIO_Pin_4;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;

GPIO_Init(GPIOA, &GPIO_InitStructure);

使用特权

评论回复
16
为你转身| | 2022-3-31 16:28 | 只看该作者
通过将NSS配置为GPIO,在通过SPI操作从设备时,就可以通过软件来选中和释放从设备了。虽然比起硬件自动置位要麻烦,但问题毕竟解决了。

进一步阅读长达900页的Manual,我发现,文中对于SPI hard模式的描述并非大多数人所认为的硬件SPI

使用特权

评论回复
17
为你转身| | 2022-3-31 16:32 | 只看该作者
原文如下:



Slave select (NSS) pin management

There are two NSS modes:

● Software NSS mode: this mode is enabled by setting the SSM bit in the SPI_CR1

register (see Figure 209). In this mode, the external NSS pin is free for other

application uses and the internal NSS signal level is driven by writing to the SSI bit in

the SPI_CR1 register.

● Hardware NSS mode: there are two cases:

– NSS output is enabled: when the STM32F20xxx is operating as a Master and the

NSS output is enabled through the SSOE bit in the SPI_CR2 register, the NSS pin

is driven low and all the NSS pins of devices connected to the Master NSS pin see

a low level and become slaves when they are configured in NSS hardware mode.

When an SPI wants to broadcast a message, it has to pull NSS low to inform all

others that there is now a master for the bus. If it fails to pull NSS low, this means

that there is another master communicating, and a Hard Fault error occurs.

– NSS output is disabled: the multimaster capability is allowed.

使用特权

评论回复
18
为你转身| | 2022-3-31 16:33 | 只看该作者
当SPI配置为hard模式后,通过检测NSS可以实现的是自身主机和从机模式的切换,而不是大多数人所认为的自动NSS。。。也就是说:在一个多SPI系统中,STM32 SPI通过NSS检测,一旦发现系统中无NSS低信号,自己就输出低,从而成为主机;当系统中有NSS低信号时(及已经有其它SPI宣布为主机),自己就配置为从机。 所谓的hard模式的NSS,实际就是为了实现多机间通信的。

使用特权

评论回复
19
为你转身| | 2022-3-31 16:34 | 只看该作者
Manual要仔细研读。

STM32的SPI NSS不论是配置为soft还是hard都是无法自动置位的,但这却是大多数应用所需要的。正如ST 论坛上RichardE所说:“Everything would be done by the peripheral. Fire and forget.”

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

39

主题

253

帖子

0

粉丝