2021年10月

使用STM32的定时器进行外部计数

使用ETR引脚的输入信号作为计数时钟,本例程使用TIM2,其ETR输入引脚为PA0,该引脚工作模式为输入模式,定时器的工作模式为从模式;另外使用PC6输出一模拟方波时钟信号。
测试时将PA6与PA0短接。(用户也可另外连接一个时钟信号到PA0引脚上。)

代码见下:
int main(void)
{

unsigned char i_Loop;
unsigned char n_Counter;

RCC_Configuration();       // System Clocks Configuration
NVIC_Configuration();       // NVIC configuration
GPIO_Configuration();       // Configure the GPIO ports

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = 0x00;
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);       // Time base configuration

TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0);

TIM_SetCounter(TIM2, 0);
TIM_Cmd(TIM2, ENABLE);

for(i_Loop = 0; i_Loop < 100; i_Loop ++) {
   GPIO_SetBits(GPIOA, GPIO_Pin_6);
   Delay(10);
   GPIO_ResetBits(GPIOA, GPIO_Pin_6);
   Delay(10);
}

n_Counter = TIM_GetCounter(TIM2);
while (1) {
}

}

前三行进行了时钟、中断、和I/O口的配置。然后进行Timer的基本配置,计数器自动装载值为0xFFFF,计
数频率不分频,定时器时钟(CK_INT)频率与数字滤波器(ETR,TIx)使用的采样频率之间的分频比为1,计数
器向上计数。
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0);
使用ETR时钟作为计数时钟需要设置为外部时钟模式2,故调用该函数,在设置时
1、关闭预分频:TIM_ExtTRGPSC_OFF。可选项:
TIM_ExtTRGPSC_OFF 0x0000
TIM_ExtTRGPSC_DIV2 0x1000
TIM_ExtTRGPSC_DIV4 0x2000
TIM_ExtTRGPSC_DIV8 0x3000
2、外部触发极性ETR不反相,高电平或上升沿有效:TIM_ExtTRGPolarity_NonInverted。可选项:
TIM_ExtTRGPolarity_Inverted和TIM_ExtTRGPolarity_NonInverted。
3、外部触发无滤波器:0000。
可选项:

0:无滤波器,以fDTS采样

1:采样频率fSAMPLING=fCK_INT,N=2
2:采样频率fSAMPLING=fCK_INT,N=4
3:采样频率fSAMPLING=fCK_INT,N=8
4:采样频率fSAMPLING=fDTS/2,N=6
5:采样频率fSAMPLING=fDTS/2,N=8
6:采样频率fSAMPLING=fDTS/4,N=6
7:采样频率fSAMPLING=fDTS/4,N=8
8:采样频率fSAMPLING=fDTS/8,N=6
9:采样频率fSAMPLING=fDTS/8,N=8
10:采样频率fSAMPLING=fDTS/16,N=5
11:采样频率fSAMPLING=fDTS/16,N=6
12:采样频率fSAMPLING=fDTS/16,N=8
13:采样频率fSAMPLING=fDTS/32,N=5
14:采样频率fSAMPLING=fDTS/32,N=6
15:采样频率fSAMPLING=fDTS/32,N=8

TIM_SetCounter(TIM2, 0);
初始化Timer的计数器初始值为0;
TIM_Cmd(TIM2, ENABLE);
启动Timer2,模拟一个方波时钟信号,输出100个Clock在PC6上。此时PA1接收到该波形,Timer2开始计数,计数结果保存在Timer的计数寄存器(Counter Register)中。通过TIM_GetCounter(TIM2)读出

下面是TIM3 CH1(对应PA6)、CH2(对应PA7)通道外部计数。
PA6或PA7作为TIM3的外部时钟引脚,需要将PA6或PA7设置为上拉输入模式。
void tim3_init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 110; //0xFFFF
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // Time base configuration

//设置TIM3外部时钟信号:TIM_TS_TI1FP1
TIM_TIxExternalClockConfig(TIM3, TIM_TS_TI1FP1, TIM_ICPolarity_Falling, 0); //TIM_ICPolarity_Rising

TIM_SetCounter(TIM3, 0);
TIM_Cmd(TIM3, ENABLE);
}

插件:
1.Elementor website builder 网页编辑工具
2.Envato 众多免费的网页模板

主题:

  1. Astra
  2. Kadence 非常简洁的blog主题,同时还具体免费的网页模板,Print Shop是一个不错的产品模板
  3. Blocksy 默认非常简洁的blog主题,同时还具体免费的网页模板(需要安装Blocksy Companion,然后出现Starter site),其中Homi模板是一个家居营销模板

1.MariaDB 10.3 的配置文件:
/etc/my.cnf.d/mariadb-server.cnf

2.MariaDB 10.3 的经典配置

#提交事务的时候,把 redo 日志写入磁盘文件对应的 os cache 缓存里去,而不是直接进入磁盘文件
innodb_flush_log_at_trx_commit=2
#该参数控制着二进制日志写入磁盘的过程,每写1000次操作系统缓冲就执行一次刷新操作
sync_binlog=1000

character-set-client-handshake = FALSE
#字符集设置
character_set_client    = utf8mb4
character_set_server = utf8mb4
#collation_server = utf8mb4_unicode_ci
  1. 查询字符集:

    SHOW VARIABLES WHERE Variable_name LIKE 'character_set_%' OR Variable_name LIKE 'collation%'

    MariaDB 10.3字符集如下:
    Variable_nameValue
    character_set_clientutf8
    character_set_connectionutf8
    character_set_databasegbk
    character_set_filesystembinary
    character_set_resultsutf8
    character_set_serverlatin1
    character_set_systemutf8
    character_sets_dir/usr/share/mariadb/charsets/
    collation_connectionutf8_general_ci
    collation_databasegbk_chinese_ci
    collation_serverlatin1_swedish_ci
  2. 如果需要进行中文字符按拼音排序,需要在创建数据库时指定字符集GBK,默认按拼音排序。

    create database 数据库名 DEFAULT CHARACTER SET gbk

  3. 如果某个数据库的字符集为utf8,需要先对字段进行转码然后排序:

    SELECT * FROM 表名
    ORDER BY CONVERT(排序字段名 using gbk);

  4. 测试案例:
    create database test DEFAULT CHARACTER SET gbk
    create table aa(id int , name varchar(20));

insert into aa(id,name) values(1,'张三');
insert into aa(id,name) values(2,'李四');
insert into aa(id,name) values(3,'王五');
insert into aa(id,name) values(4,'陈六');
insert into aa(id,name) values(5,'赵明');
insert into aa(id,name) values(6,'魃ba明');
insert into aa(id,name) values(7,'魈xiao明');
insert into aa(id,name) values(8,'鬾qi明');
insert into aa(id,name) values(9,'bb');
insert into aa(id,name) values(10,'aa');

select * from aa ordy by name;

执行力是成功的必要因素,先做了再说

“执行力”就是按质按量的完成工作的能力。执行力是一个人最重要的能力,因为你所有的想法、计划在没有执行的情况下都是不成立的。

对于个人执行力来说,两个要素构成:
A、个人能力和工作态度,
B、能力是基础,态度是关键。

每个人的能力是不同的,有的人可以通过学习提高自己的能力,而有的人根本不明白能力也是可以通过学习来提升的,其实最重要的还是态度,我们要时刻摆正自己的态度。

个人执行力的缺失原因

1、拖延磨唧,缺乏行动
“最消磨意志、最摧毁创造力的事情,莫过于拥有梦想而不开始行动”。拖延不会让事情凭空消失,只会使普通的事情变成紧急的事情。拖延消磨了意志,使人丧失进取心。一旦开始遇事推拖,就很容易再次拖延,直到变成一种根深蒂固的习惯。拖延,只能让他人领先。任何憧憬、理想和计划,都会在拖延中落空。

2、优柔寡断、不敢决策
如同马云说的一样,很多人晚上想想千条路,早上起来走原路!如果优柔寡断,不敢决策,则会徒徒失去许多机会。

3、意志不够坚定,缺乏毅力,不能吃苦
不能吃苦,没有毅力,没有坚决完成任务的坚强信念,遇到困难时往往选择逃避,而不是勇敢面对、积极寻找方法或者寻求帮助。

提升个人执行力的方法
1、绝不拖延,立即行动
行动未必带来好的结果,但不行动就永远不会有结果。
行动,撬动梦想。说一尺、不如做一寸,想一丈、不如做一尺,任何事都立刻去做的人才是伟大的人。
什么事情不怕自己不懂,只怕自己不做,边做边学,总会有成绩的。因此,要做行动的巨人!

2、不要迟疑,当机立断
哥伦布说:“即使决定是错误的,那我们也可以通过执行来把事情做对,而不是再回头讨论”。如果我们总是希望能把事情考虑周全以后再行动,这固然没错,但这也是瞻前顾后、你犹豫不决的体现。我们做事不能当机立断,一旦犹豫不决的时候,我们便会畏缩。畏缩就无法前进,就会失去很多机会,就会徒徒蹉跎时光,留下悔念。

3、磨练意志,培养毅力
遇到困难或挫折,要有“啃下硬骨头”的勇气和决心,绝不轻易放弃!

include <stdio.h>

include <stm32f10x.h>

int fputc(int ch, FILE *fp)
{

if (fp == stdout)
{
    if (ch == '\n')
    {
        while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
        USART_SendData(USART1, '\r');
    }
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    USART_SendData(USART1, ch);
}
return ch;

}

// 发送开始信号和从机地址(传输模式)
void start(void)
{

if (I2C1->SR1 || I2C1->SR2)
    printf("error!\n");

restart:

I2C_GenerateSTART(I2C1, ENABLE);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) == ERROR); // 等待开始信号发送完毕
I2C_SendData(I2C1, 0xa0); // 从机地址(传输模式)
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR) // 等待从机确认
{
    if (I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == SET)
    {
        // 若从机未响应, 则重试
        // 执行了写操作后需要等待一段时间才能执行其他命令
        I2C_ClearFlag(I2C1, I2C_FLAG_AF);
        //printf("NACK!\n");
        goto restart;
    }
}

}

uint8_t read(uint8_t addr)
{

start();
I2C_SendData(I2C1, addr); // 发送存储器地址
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR);

I2C_GenerateSTART(I2C1, ENABLE); // RESTART
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
I2C_SendData(I2C1, 0xa1); // 从机地址(接收模式)
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) == ERROR);

I2C_GenerateSTOP(I2C1,ENABLE); // 接收最后一字节数据前先准备好STOP信号
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED) == ERROR); // 等待数据接收完毕
while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET); // 等待停止信号发送完毕
return I2C_ReceiveData(I2C1);

}

void write(uint8_t addr, uint8_t value)
{

start();
I2C_SendData(I2C1, addr); // 前两个数据可连发, 无需等待TXE置位
I2C_SendData(I2C1, value);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR); // 等待数据完全发送完毕
I2C_GenerateSTOP(I2C1,ENABLE);
while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET); // 等待停止信号发送完毕

}

void read_more(uint8_t addr, char *data, uint8_t len)
{

start();
I2C_SendData(I2C1, addr);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR);

I2C_GenerateSTART(I2C1, ENABLE);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
I2C_SendData(I2C1, 0xa1);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) == ERROR);

I2C_AcknowledgeConfig(I2C1, ENABLE);
while (len--)
{
    if (len == 0)
    {
        I2C_AcknowledgeConfig(I2C1, DISABLE);
        I2C_GenerateSTOP(I2C1,ENABLE); // 接收最后一字节数据前先准备好STOP信号
    }
    while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED) == ERROR); // 等待当前数据接收完毕
    *data++ = I2C_ReceiveData(I2C1);
}
while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET); // 等待停止信号发送完毕

}

void write_more(uint8_t addr, const char *data, uint8_t len)
{

start();
I2C_SendData(I2C1, addr);
while (len--)
{
    I2C_SendData(I2C1, *data++);
    while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING) == ERROR); // 等待TXE
}
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR); // 等待全部数据发送完毕
I2C_GenerateSTOP(I2C1,ENABLE);
while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET); // 等待停止信号发送完毕

}

int main(void)
{

char str[20];
GPIO_InitTypeDef gpio;
I2C_InitTypeDef i2c;
USART_InitTypeDef usart;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_USART1, ENABLE);

// 串口发送引脚设为复用推挽输出
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Pin = GPIO_Pin_9;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio);

// I2C引脚设为复用开漏输出
gpio.GPIO_Mode = GPIO_Mode_AF_OD;
gpio.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_Init(GPIOB, &gpio);

USART_StructInit(&usart);
usart.USART_BaudRate = 115200;
usart.USART_Mode = USART_Mode_Tx;
USART_Init(USART1, &usart);
USART_Cmd(USART1, ENABLE);

I2C_StructInit(&i2c);
i2c.I2C_ClockSpeed = 100000;
I2C_Init(I2C1, &i2c);
I2C_Cmd(I2C1, ENABLE);

write(17, 0x31);
printf("read: 0x%02x\n", read(17));

write_more(17, "Hello!", 7); // 区域16~23
read_more(17, str, sizeof(str));
printf("str: %s\n", str);

write_more(8, "12345678ABCDEFG", 16); // 先将前8个字符写入地址8~15处, 然后回到地址8处写入剩下的字符, 包括最后的\0
read_more(8, str, sizeof(str));
printf("str: %s\n", str);

printf("I2C1->SR1=0x%04x, I2C1->SR2=0x%04x\n", I2C_ReadRegister(I2C1, I2C_Register_SR1), I2C_ReadRegister(I2C1, I2C_Register_SR2));
while (1)
    __WFI();

}
【程序运行结果1】
read: 0x31
str: Hello!
str: ABCDEFG
I2C1->SR1=0x0000, I2C1->SR2=0x0000
两个SR寄存器的值都为0表明I2C正常工作。