硬汉嵌入式论坛

 找回密码
 立即注册
查看: 3778|回复: 29
收起左侧

日常灌水帖

  [复制链接]

14

主题

207

回帖

254

积分

高级会员

积分
254
发表于 2018-3-8 23:09:24 | 显示全部楼层 |阅读模式
本来计划等六月份开发板大佬都推出RT后选一款RT开发板学学,日常关注感觉RT起伏不定,目前印象:价格低、bug略多。
关于RT再继续日常关注,受综合例程特别是二代示波器吸引,刚买了V6,准备开搞,此帖准备作为日常灌水帖,希望起个刺激推动作用吧。

评分

参与人数 1金币 +100 收起 理由
eric2013 + 100 很给力!

查看全部评分

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106738
QQ
发表于 2018-3-9 02:32:21 | 显示全部楼层
先给楼主一个精华,之前楼主的那个C++的,弄得就非常好,欢迎楼主发帖、纪录、交流。
回复

使用道具 举报

14

主题

207

回帖

254

积分

高级会员

积分
254
 楼主| 发表于 2018-3-9 22:09:10 | 显示全部楼层
这个精华来的猝不及防啊
本来打算签个到简单灌灌水之类的,看来要加点料了
明天去公司加班兼下载资料,各项齐全准备开搞
感谢eric2013给予精华,向硬汉致敬!
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106738
QQ
发表于 2018-3-10 02:15:22 | 显示全部楼层
龙之谷 发表于 2018-3-9 22:09
这个精华来的猝不及防啊
本来打算签个到简单灌灌水之类的,看来要加点料了
明天去公司加班兼下载资料,各 ...

回复

使用道具 举报

14

主题

207

回帖

254

积分

高级会员

积分
254
 楼主| 发表于 2018-3-11 22:06:25 | 显示全部楼层
2018-03-11
开发板资料昨天晚上下载完成。开发板买回来几天了,今天刚拆,出厂程序OK。
花了两三个小时浏览了下软件开发手册和硬件开发手册,感觉:涉及内容多,干货不啰嗦。
回复

使用道具 举报

14

主题

207

回帖

254

积分

高级会员

积分
254
 楼主| 发表于 2018-3-16 22:54:47 | 显示全部楼层
先暂停一下,这段时间事比较多,忙过这阵再开始。预计短则一两周,长则一个月。
回复

使用道具 举报

6

主题

130

回帖

148

积分

初级会员

积分
148
发表于 2018-3-17 17:30:17 | 显示全部楼层
龙之谷 发表于 2018-3-16 22:54
先暂停一下,这段时间事比较多,忙过这阵再开始。预计短则一两周,长则一个月。

别真的灌水了
回复

使用道具 举报

14

主题

207

回帖

254

积分

高级会员

积分
254
 楼主| 发表于 2018-3-22 22:50:45 | 显示全部楼层
001
今天公司电脑装上了Source Insight && UltraEdit && Beyond Compare,并简单使用了一下,尤其Beyond Compare真是以前遇到问题时想用而不知道的软件,长见识了。
LED灯试验:
①对常用又常变量的封装,main函数开始三个宏定义:
/* 定义例程名和例程发布日期 */
#define EXAMPLE_NAME        "V6-不一样的跑马灯(软件定时器、状态机)"
#define EXAMPLE_DATE        "2015-12-12"
#define DEMO_VER                "1.0"
放进PrintfLogo函数
printf("* 例程名称   : %s\r\n", EXAMPLE_NAME);        /* 打印例程名称 */
printf("* 例程版本   : %s\r\n", DEMO_VER);                /* 打印例程版本 */
printf("* 发布日期   : %s\r\n", EXAMPLE_DATE);        /* 打印例程日期 */
干的漂亮;
②状态相关使用单词status,变量使用g_MainStatus,状态函数使用Status_x();使用了匈牙利命名法,善于在变量名命中加_,程序读起来很规整,看着舒服,琢磨下,自身亟待改进。
③三个状态函数Status_x();的模式类似操作系统模式,运用倒是灵活。
关于程序里定时器部分,稍后再说,本来以为用的是硬件定时器,理不出来,结果看到被嘀嗒定时器调用,恍然大明白,也是蛮有意思的。
只表述下个人感受,确实挺有意思的。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106738
QQ
发表于 2018-3-23 01:31:16 | 显示全部楼层
龙之谷 发表于 2018-3-22 22:50
001
今天公司电脑装上了Source Insight && UltraEdit && Beyond Compare,并简单使用了一下,尤其Beyond C ...

Source Insight 是好东西,这里有最新的4.x版本:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=82497
回复

使用道具 举报

14

主题

207

回帖

254

积分

高级会员

积分
254
 楼主| 发表于 2018-3-23 23:02:47 | 显示全部楼层
002
初看bsp_timer的时候,竟会有些迷茫,有点云里雾里,主要原因在于这个文件处理内容较多,并且包含SOFT_TMR结构体操作的定时器是用嘀嗒定时器作为时基,在此基础使用C语言编写出定时逻辑,而非直接使用硬件定时器,知道这点很重要,原来就是因为钻牛角尖,找不到和硬件定时器的衔接而不知所言。
通读下来,定时器的程序功能强大而简练,逻辑严谨不失优美,爽。
为了理清逻辑,特制作了思维导图,本打算使用电脑完成,无奈电脑装的Mind Manager竟没有手机的好用、好看,手机打字略微繁琐,所以本可以把导图做的逻辑更清晰、丰富,但实在太过费力,就此为止吧。
bsp_timer.jpg

评分

参与人数 1金币 +50 收起 理由
eric2013 + 50 很给力!

查看全部评分

回复

使用道具 举报

14

主题

207

回帖

254

积分

高级会员

积分
254
 楼主| 发表于 2018-3-26 23:13:02 | 显示全部楼层
又看了遍按键例程,住处电脑太卡,软件用的也不顺手,稍后到公司抽个非工作时间找下有没有比较好的软件可用。
回复

使用道具 举报

7

主题

70

回帖

91

积分

初级会员

积分
91
发表于 2018-3-28 11:38:35 | 显示全部楼层
看了楼主介绍,对Systick这一部分稍有理解,看V5教程感觉写的不错
回复

使用道具 举报

14

主题

207

回帖

254

积分

高级会员

积分
254
 楼主| 发表于 2018-3-28 23:29:48 | 显示全部楼层
003
找了几个软件,并不是很顺手,很多功能需要交费才能使用,算了,自己简易搞下吧。
关于bsp_key,有两点理顺了,程序也就明了啦。
第一点:结构体
/*
        每个按键对应1个全局的结构体变量。
*/
typedef struct
{
        /* 下面是一个函数指针,指向判断按键手否按下的函数 */
        uint8_t (*IsKeyDownFunc)(void); /* 按键按下的判断函数,1表示按下 */

        uint8_t  Count;                        /* 滤波器计数器 */
        uint16_t LongCount;                /* 长按计数器 */
        uint16_t LongTime;                /* 按键按下持续时间, 0表示不检测长按 */
        uint8_t  State;                        /* 按键当前状态(按下还是弹起) */
        uint8_t  RepeatSpeed;        /* 连续按键周期 */
        uint8_t  RepeatCount;        /* 连续按键计数器 */
}KEY_T;

第二点:被周期调用的bsp_DetectKey函数,此过程稍复杂,需要耐心理解。
bsp_key.jpg
这两点理解以后,其它内容掌握就比较顺畅了。

评分

参与人数 1金币 +100 收起 理由
eric2013 + 100 很给力!

查看全部评分

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106738
QQ
发表于 2018-3-29 00:38:06 | 显示全部楼层
整理的非常给力
回复

使用道具 举报

14

主题

207

回帖

254

积分

高级会员

积分
254
 楼主| 发表于 2018-3-29 21:39:52 | 显示全部楼层

谢硬汉鼓励
回复

使用道具 举报

14

主题

207

回帖

254

积分

高级会员

积分
254
 楼主| 发表于 2018-4-6 22:26:56 | 显示全部楼层
004
关于bsp_uart_fifo,多个串口可同时工作,串口3实现功能更为具体,以此为例:
一、基础定义
        1.宏定义端口信息
                /* 串口3的GPIO - RS485 */
                #define UART3_TX_PORT      GPIOB
                #define UART3_TX_PIN       GPIO_Pin_10
                #define UART3_TX_CLK       RCC_AHB1Periph_GPIOB
                #define UART3_TX_SOURCE    GPIO_PinSource10

                #define UART3_RX_PORT      GPIOCB
                #define UART3_RX_PIN       GPIO_Pin_11
                #define UART3_RX_CLK       RCC_AHB1Periph_GPIOB
                #define UART3_RX_SOURCE    GPIO_PinSource11

        2.定义串口结构体,规范清晰全面
                typedef struct
                {
                        USART_TypeDef *uart;                /* STM32内部串口设备指针 */
                        uint8_t *pTxBuf;                        /* 发送缓冲区 */
                        uint8_t *pRxBuf;                        /* 接收缓冲区 */
                        uint16_t usTxBufSize;                /* 发送缓冲区大小 */
                        uint16_t usRxBufSize;                /* 接收缓冲区大小 */
                        __IO uint16_t usTxWrite;        /* 发送缓冲区写指针 */
                        __IO uint16_t usTxRead;                /* 发送缓冲区读指针 */
                        __IO uint16_t usTxCount;        /* 等待发送的数据个数 */

                        __IO uint16_t usRxWrite;        /* 接收缓冲区写指针 */
                        __IO uint16_t usRxRead;                /* 接收缓冲区读指针 */
                        __IO uint16_t usRxCount;        /* 还未读取的新数据个数 */

                        void (*SendBefor)(void);         /* 开始发送之前的回调函数指针(主要用于RS485切换到发送模式) */
                        void (*SendOver)(void);         /* 发送完毕的回调函数指针(主要用于RS485将发送模式切换为接收模式) */
                        void (*ReciveNew)(uint8_t _byte);        /* 串口收到数据的回调函数指针 */
        }UART_T;

        3.①.c文件定义缓冲区
                #if UART3_FIFO_EN == 1
                        static UART_T g_tUart3;
                        static uint8_t g_TxBuf3[UART3_TX_BUF_SIZE];                /*发送缓冲区 /
                        static uint8_t g_RxBuf3[UART3_RX_BUF_SIZE];                /*接收缓冲区 */
                #endif

        ②.h文件定义缓冲区大小
                #if UART3_FIFO_EN == 1
                        #define UART3_BAUD                        9600
                        #define UART3_TX_BUF_SIZE        1*1024
                        #define UART3_RX_BUF_SIZE        1*1024
                #endif
               
        4.枚举端口
                /* 定义端口号 */
                typedef enum
                {
                        COM1 = 0,        /* USART1  PA9, PA10 或  PB6, PB7*/
                        COM2 = 1,        /* USART2, PD5,PD6 或 PA2, PA3 */
                        COM3 = 2,        /* USART3, PB10, PB11 */
                        COM4 = 3,        /* UART4, PC10, PC11 */
                        COM5 = 4,        /* UART5, PC12, PD2 */
                        COM6 = 5        /* USART6, PC6, PC7 */
                }COM_PORT_E;

二、应用配置
        1.结构体赋值对接
                #if UART3_FIFO_EN == 1
                        g_tUart3.uart = USART3;                                                /* STM32 串口设备 */
                        g_tUart3.pTxBuf = g_TxBuf3;                                        /* 发送缓冲区指针 */
                        g_tUart3.pRxBuf = g_RxBuf3;                                        /* 接收缓冲区指针 */
                        g_tUart3.usTxBufSize = UART3_TX_BUF_SIZE;        /* 发送缓冲区大小 */
                        g_tUart3.usRxBufSize = UART3_RX_BUF_SIZE;        /* 接收缓冲区大小 */
                        g_tUart3.usTxWrite = 0;                                                /* 发送FIFO写索引 */
                        g_tUart3.usTxRead = 0;                                                /* 发送FIFO读索引 */
                        g_tUart3.usRxWrite = 0;                                                /* 接收FIFO写索引 */
                        g_tUart3.usRxRead = 0;                                                /* 接收FIFO读索引 */
                        g_tUart3.usRxCount = 0;                                                /* 接收到的新数据个数 */
                        g_tUart3.usTxCount = 0;                                                /* 待发送的数据个数 */
                        g_tUart3.SendBefor = RS485_SendBefor;                /* 发送数据前的回调函数 */
                        g_tUart3.SendOver = RS485_SendOver;                        /* 发送完毕后的回调函数 */
                        g_tUart3.ReciveNew = RS485_ReciveNew;                /* 接收到新数据后的回调函数 */
                #endif
                其中,包含钩子函数定义原型:
                void RS485_SendBefor(void);
                void RS485_SendOver(void);
                void RS485_ReciveNew(uint8_t _byte);

        2.枚举变量转换
                ①COM端口号转换为UART指针
                /*
                *********************************************************************************************************
                *        函 数 名: ComToUart
                *        功能说明: 将COM端口号转换为UART指针
                *        形    参: _ucPort: 端口号(COM1 - COM6)
                *        返 回 值: uart指针
                *********************************************************************************************************
                */
                UART_T *ComToUart(COM_PORT_E _ucPort)
                {
                        if (_ucPort == COM1)
                        {
                                #if UART1_FIFO_EN == 1
                                        return &g_tUart1;
                                #else
                                        return 0;
                                #endif
                        }
                        else if (_ucPort == COM2)
                        {
                                #if UART2_FIFO_EN == 1
                                        return &g_tUart2;
                                #else
                                        return;
                                #endif
                        }
                        else if (_ucPort == COM3)
                        {
                                #if UART3_FIFO_EN == 1
                                        return &g_tUart3;
                                #else
                                        return 0;
                                #endif
                        }
                        else if (_ucPort == COM4)
                        {
                                #if UART4_FIFO_EN == 1
                                        return &g_tUart4;
                                #else
                                        return 0;
                                #endif
                        }
                        else if (_ucPort == COM5)
                        {
                                #if UART5_FIFO_EN == 1
                                        return &g_tUart5;
                                #else
                                        return 0;
                                #endif
                        }
                        else if (_ucPort == COM6)
                        {
                                #if UART6_FIFO_EN == 1
                                        return &g_tUart6;
                                #else
                                        return 0;
                                #endif
                        }
                        else
                        {
                                /* 不做任何处理 */
                                return 0;
                        }
                }
                转换应用
                /*
                *********************************************************************************************************
                *        函 数 名: comSendBuf
                *        功能说明: 向串口发送一组数据。数据放到发送缓冲区后立即返回,由中断服务程序在后台完成发送
                *        形    参: _ucPort: 端口号(COM1 - COM6)
                *                          _ucaBuf: 待发送的数据缓冲区
                *                          _usLen : 数据长度
                *        返 回 值: 无
                *********************************************************************************************************
                */
                void comSendBuf(COM_PORT_E _ucPort, uint8_t *_ucaBuf, uint16_t _usLen)
                {
                        UART_T *pUart;

                        pUart = ComToUart(_ucPort);
                        if (pUart == 0)
                        {
                                return;
                        }

                        if (pUart->SendBefor != 0)
                        {
                                pUart->SendBefor();                /* 如果是RS485通信,可以在这个函数中将RS485设置为发送模式 */
                        }

                        UartSend(pUart, _ucaBuf, _usLen);
                }

                ②端口号转换为USART_Typedef* USARTx
                /*
                *********************************************************************************************************
                *        函 数 名: ComToUart
                *        功能说明: 将COM端口号转换为 USART_TypeDef* USARTx
                *        形    参: _ucPort: 端口号(COM1 - COM6)
                *        返 回 值: USART_TypeDef*,  USART1, USART2, USART3, UART4, UART5
                *********************************************************************************************************
                */
                USART_TypeDef *ComToUSARTx(COM_PORT_E _ucPort)
                {
                        if (_ucPort == COM1)
                        {
                                #if UART1_FIFO_EN == 1
                                        return USART1;
                                #else
                                        return 0;
                                #endif
                        }
                        else if (_ucPort == COM2)
                        {
                                #if UART2_FIFO_EN == 1
                                        return USART2;
                                #else
                                        return;
                                #endif
                        }
                        else if (_ucPort == COM3)
                        {
                                #if UART3_FIFO_EN == 1
                                        return USART3;
                                #else
                                        return 0;
                                #endif
                        }
                        else if (_ucPort == COM4)
                        {
                                #if UART4_FIFO_EN == 1
                                        return USART4;
                                #else
                                        return 0;
                                #endif
                        }
                        else if (_ucPort == COM5)
                        {
                                #if UART5_FIFO_EN == 1
                                        return USART5;
                                #else
                                        return 0;
                                #endif
                        }
                        else
                        {
                                /* 不做任何处理 */
                                return 0;
                        }
                }
                转换应用
                /*
                *********************************************************************************************************
                *        函 数 名: comSetBaud
                *        功能说明: 设置串口的波特率
                *        形    参: _ucPort: 端口号(COM1 - COM5)
                *                          _BaudRate: 波特率,0-4500000, 最大4.5Mbps
                *        返 回 值: 无
                *********************************************************************************************************
                */
                void comSetBaud(COM_PORT_E _ucPort, uint32_t _BaudRate)
                {
                        USART_TypeDef* USARTx;
                        
                        USARTx = ComToUSARTx(_ucPort);
                        if (USARTx == 0)
                        {
                                return;
                        }
                        
                        USART_SetBaudRate(USARTx, _BaudRate);
                }
                其中
                /*
                *********************************************************************************************************
                *        函 数 名: USART_SetBaudRate
                *        功能说明: 修改波特率寄存器,不更改其他设置。如果使用 USART_Init函数, 则会修改硬件流控参数和RX,TX配置
                *                          根据固件库中 USART_Init函数,将其中配置波特率的部分单独提出来封装为一个函数
                *        形    参: USARTx : USART1, USART2, USART3, UART4, UART5
                *                          BaudRate : 波特率,取值 0 - 4500000
                *        返 回 值: 无
                *********************************************************************************************************
                */
                void USART_SetBaudRate(USART_TypeDef* USARTx, uint32_t BaudRate);
                至此,整个框架实现。PS:最近工作比较忙,有些疲,长坐伤身,道友也注意锻炼下身体。

评分

参与人数 1金币 +100 收起 理由
eric2013 + 100 赞一个!

查看全部评分

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106738
QQ
发表于 2018-4-7 01:10:22 | 显示全部楼层
给力!
回复

使用道具 举报

14

主题

207

回帖

254

积分

高级会员

积分
254
 楼主| 发表于 2018-4-7 23:48:37 | 显示全部楼层
005
今天灌点水
外部中断两步骤:
1.配置
        /* 配置PI8 */
        {
                GPIO_InitTypeDef GPIO_InitStructure;
                EXTI_InitTypeDef   EXTI_InitStructure;
                NVIC_InitTypeDef   NVIC_InitStructure;               
               
                /* 使能 GPIO 时钟 */
                RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOI, ENABLE);
                /* Enable SYSCFG clock */
                RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
               
                /* Configure PI8 pin as input floating */
                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
                GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
                GPIO_Init(GPIOA, &GPIO_InitStructure);

                 /* Connect EXTI Line8 to PI8 pin */
                SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOI, EXTI_PinSource8);

                /* Configure EXTI8 line */
                EXTI_InitStructure.EXTI_Line = EXTI_Line8;
                EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
                EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;          /* 上升沿触发 */
                EXTI_InitStructure.EXTI_LineCmd = ENABLE;
                EXTI_Init(&EXTI_InitStructure);

                /* Enable and set EXTI8 Interrupt to the lowest priority */
                NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
                NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
                NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
                NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
                NVIC_Init(&NVIC_InitStructure);
        }
2.中断
        /*
        *********************************************************************************************************
        *        函 数 名: EXTI9_5_IRQHandler
        *        功能说明: 外部中断服务程序
        *        形    参:无
        *        返 回 值: 无
        *********************************************************************************************************
        */
        void EXTI9_5_IRQHandler(void)
        {
                /* PI8, K1按键按下 */
                if (EXTI_GetITStatus(EXTI_Line8) != RESET)
                {
                        bsp_LedToggle(1);
                       
                        EXTI_ClearITPendingBit(EXTI_Line8);
                       
                        printf("PI8 中断\r\n");
                }
        }

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106738
QQ
发表于 2018-4-8 01:32:13 | 显示全部楼层
来支持下楼主
回复

使用道具 举报

14

主题

207

回帖

254

积分

高级会员

积分
254
 楼主| 发表于 2018-4-8 10:40:11 | 显示全部楼层
回复

使用道具 举报

14

主题

207

回帖

254

积分

高级会员

积分
254
 楼主| 发表于 2018-4-8 12:30:42 | 显示全部楼层
006
bsp_beep
一、分析结构体,依旧对结构体定义很感兴趣
bsp_beep.jpg
二、阅读程序,发现两处存疑
1.g_tBeep.ucMute控制的暂停和继续,都是调用BEEP_Stop();函数,只有停止,如何恢复继续?
存疑之一.png
2.void BEEP_Pro(void)函数中,g_tBeep.usStopTime变量的判断处理,前边有判断g_tBeep.usStopTime == 0时,return处理,后续又有if (g_tBeep.usStopTime > 0)        /* 间断发声 */判断,处理有冗余。
存疑之二.png
三、整体来说,beep处理还是很有意思的,处理流程巧妙,爽利
/**********************************************************************************************************
*        函 数 名: BEEP_Pro
*        功能说明: 每隔10ms调用1次该函数,用于控制蜂鸣器发声。该函数在 bsp_timer.c 中被调用。
*        形    参: 无
*        返 回 值: 无
**********************************************************************************************************/
void BEEP_Pro(void)
{
        if ((g_tBeep.ucEnalbe == 0) || (g_tBeep.usStopTime == 0) || (g_tBeep.ucMute == 1))
        {
                return;
        }
       
        if (g_tBeep.ucState == 0)     //鸣叫状态期间处理
        {
                if (g_tBeep.usStopTime > 0)        /* 间断发声 */
                {
                        if (++g_tBeep.usCount >= g_tBeep.usBeepTime)
                        {
                                BEEP_DISABLE();                /* 停止发声 */
                                g_tBeep.usCount = 0;
                                g_tBeep.ucState = 1;
                        }
                }
                else
                {
                        ;        /* 不做任何处理,连续发声 */
                }
        }
        else if (g_tBeep.ucState == 1)     //停止鸣叫期间处理
        {
                if (++g_tBeep.usCount >= g_tBeep.usStopTime)
                {                       
                        if (g_tBeep.usCycle > 0)     //有鸣叫次数设置,非持续鸣叫
                        {
                                if (++g_tBeep.usCycleCount >= g_tBeep.usCycle)
                                {
                                        /* 循环次数到,停止发声 */
                                        g_tBeep.ucEnalbe = 0;
                                }

                                if (g_tBeep.ucEnalbe == 0)
                                {
                                        g_tBeep.usStopTime = 0;
                                        return;
                                }
                        }
                        else
                       {
                                ;  /* 连续发声时,直到调用stop停止为止 */
                       }

                        g_tBeep.usCount = 0;
                        g_tBeep.ucState = 0;

                        BEEP_ENABLE();                        /* 开始发声 */
                }
        }
}

回复

使用道具 举报

14

主题

207

回帖

254

积分

高级会员

积分
254
 楼主| 发表于 2018-4-8 21:31:24 | 显示全部楼层
本帖最后由 龙之谷 于 2018-4-8 21:39 编辑

007
bsp_tim_pwm
最终主要实现、常用的有两个函数
1.配置中断函数
/*
*********************************************************************************************************
*        函 数 名: bsp_SetTIMforInt
*        功能说明: 配置TIM和NVIC,用于简单的定时中断. 开启定时中断。 中断服务程序由应用程序实现。
*        形    参: TIMx : 定时器
*                          _ulFreq : 定时频率 (Hz)。 0 表示关闭。
*                          _PreemptionPriority : 中断优先级分组
*                          _SubPriority : 子优先级
*        返 回 值: 无
*********************************************************************************************************
*/
void bsp_SetTIMforInt(TIM_TypeDef* TIMx, uint32_t _ulFreq, uint8_t _PreemptionPriority, uint8_t _SubPriority)
{
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        uint16_t usPeriod;
        uint16_t usPrescaler;
        uint32_t uiTIMxCLK;

          /* 使能TIM时钟 */
        if ((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM9) || (TIMx == TIM10) || (TIMx == TIM11))
        {
                RCC_APB2PeriphClockCmd(bsp_GetRCCofTIM(TIMx), ENABLE);
        }
        else
        {
                RCC_APB1PeriphClockCmd(bsp_GetRCCofTIM(TIMx), ENABLE);
        }

        if (_ulFreq == 0)
        {
                TIM_Cmd(TIMx, DISABLE);                /* 关闭定时输出 */
                return;
        }

    /*-----------------------------------------------------------------------
                system_stm32f4xx.c 文件中 void SetSysClock(void) 函数对时钟的配置如下:

                HCLK = SYSCLK / 1     (AHB1Periph)
                PCLK2 = HCLK / 2      (APB2Periph)
                PCLK1 = HCLK / 4      (APB1Periph)

                因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 = SystemCoreClock / 2;
                因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = PCLK2 x 2 = SystemCoreClock;

                APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13,TIM14
                APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11

        ----------------------------------------------------------------------- */
        if ((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM9) || (TIMx == TIM10) || (TIMx == TIM11))
        {
                /* APB2 定时器 */
                uiTIMxCLK = SystemCoreClock;
        }
        else        /* APB1 定时器 */
        {
                uiTIMxCLK = SystemCoreClock / 2;
        }

        if (_ulFreq < 100)
        {
                usPrescaler = 10000 - 1;                                        /* 分频比 = 1000 */
                usPeriod =  (uiTIMxCLK / 10000) / _ulFreq  - 1;                /* 自动重装的值 */
        }
        else if (_ulFreq < 3000)
        {
                usPrescaler = 100 - 1;                                        /* 分频比 = 100 */
                usPeriod =  (uiTIMxCLK / 100) / _ulFreq  - 1;                /* 自动重装的值 */
        }
        else        /* 大于4K的频率,无需分频 */
        {
                usPrescaler = 0;                                        /* 分频比 = 1 */
                usPeriod = uiTIMxCLK / _ulFreq - 1;        /* 自动重装的值 */
        }

        /* Time base configuration */
        TIM_TimeBaseStructure.TIM_Period = usPeriod;
        TIM_TimeBaseStructure.TIM_Prescaler = usPrescaler;
        TIM_TimeBaseStructure.TIM_ClockDivision = 0;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0000;                /* TIM1 和 TIM8 必须设置 */

        TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure);

        TIM_ARRPreloadConfig(TIMx, ENABLE);

        /* TIM Interrupts enable */
        TIM_ITConfig(TIMx, TIM_IT_Update, ENABLE);

        /* TIMx enable counter */
        TIM_Cmd(TIMx, ENABLE);

       /* 配置TIM定时更新中断 (Update) */
        {
                NVIC_InitTypeDef NVIC_InitStructure;        /* 中断结构体在 misc.h 中定义 */
                uint8_t irq = 0;        /* 中断号, 定义在 stm32f4xx.h */

                if ((TIMx == TIM1) || (TIMx == TIM10))
                        irq = TIM1_UP_TIM10_IRQn;
                else if (TIMx == TIM2)
                        irq = TIM2_IRQn;
                else if (TIMx == TIM3)
                        irq = TIM3_IRQn;
                else if (TIMx == TIM4)
                        irq = TIM4_IRQn;
                else if (TIMx == TIM5)
                        irq = TIM5_IRQn;
                else if (TIMx == TIM6)
                        irq = TIM6_DAC_IRQn;
                else if (TIMx == TIM7)
                        irq = TIM7_IRQn;
                else if (TIMx == TIM7)
                        irq = TIM7_IRQn;
                else if (TIMx == TIM7)
                        irq = TIM7_IRQn;
                else if ((TIMx == TIM8) || (TIMx == TIM13))
                        irq = TIM8_UP_TIM13_IRQn;
                else if (TIMx == TIM9)
                        irq = TIM1_BRK_TIM9_IRQn;
                else if (TIMx == TIM11)
                        irq = TIM1_TRG_COM_TIM11_IRQn;
                else if (TIMx == TIM12)
                        irq = TIM8_BRK_TIM12_IRQn;
                else if (TIMx == TIM12)
                        irq = TIM8_TRG_COM_TIM14_IRQn;

                NVIC_InitStructure.NVIC_IRQChannel = irq;
                NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = _PreemptionPriority;
                NVIC_InitStructure.NVIC_IRQChannelSubPriority = _SubPriority;
                NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
                NVIC_Init(&NVIC_InitStructure);
        }
}


2.设置引脚PWM输出函数
/*
*********************************************************************************************************
*        函 数 名: bsp_SetTIMOutPWM
*        功能说明: 设置引脚输出的PWM信号的频率和占空比.  当频率为0,并且占空为0时,关闭定时器,GPIO输出0;
*                          当频率为0,占空比为100%时,GPIO输出1.
*        形    参: _ulFreq : PWM信号频率,单位Hz  (实际测试,最大输出频率为 168M / 4 = 42M). 0 表示禁止输出
*                          _ulDutyCycle : PWM信号占空比,单位:万分之一。如5000,表示50.00%的占空比
*        返 回 值: 无
*********************************************************************************************************
*/
void bsp_SetTIMOutPWM(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, TIM_TypeDef* TIMx, uint8_t _ucChannel, uint32_t _ulFreq, uint32_t _ulDutyCycle)
{
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_OCInitTypeDef  TIM_OCInitStructure;
        uint16_t usPeriod;
        uint16_t usPrescaler;
        uint32_t uiTIMxCLK;

        if (_ulDutyCycle == 0)
        {               
                TIM_Cmd(TIMx, DISABLE);                /* 关闭PWM输出 */
                bsp_ConfigGpioOut(GPIOx, GPIO_Pin);        /* 配置GPIO为推挽输出 */               
                GPIO_WriteBit(GPIOx, GPIO_Pin, Bit_RESET);        /* PWM = 0 */               
                return;
        }
        else if (_ulDutyCycle == 10000)
        {
                TIM_Cmd(TIMx, DISABLE);                /* 关闭PWM输出 */

                bsp_ConfigGpioOut(GPIOx, GPIO_Pin);        /* 配置GPIO为推挽输出 */               
                GPIO_WriteBit(GPIOx, GPIO_Pin, Bit_SET);        /* PWM = 1 */        
                return;
        }
        

        bsp_ConfigTimGpio(GPIOx, GPIO_Pin, TIMx, _ucChannel);        /* 使能GPIO和TIM时钟,并连接TIM通道到GPIO */
        
    /*-----------------------------------------------------------------------
                system_stm32f4xx.c 文件中 void SetSysClock(void) 函数对时钟的配置如下:

                HCLK = SYSCLK / 1     (AHB1Periph)
                PCLK2 = HCLK / 2      (APB2Periph)
                PCLK1 = HCLK / 4      (APB1Periph)

                因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 = SystemCoreClock / 2;
                因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = PCLK2 x 2 = SystemCoreClock;

                APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM6, TIM12, TIM13,TIM14
                APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11

        ----------------------------------------------------------------------- */
        if ((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM9) || (TIMx == TIM10) || (TIMx == TIM11))
        {
                /* APB2 定时器 */
                uiTIMxCLK = SystemCoreClock;
        }
        else        /* APB1 定时器 */
        {
                uiTIMxCLK = SystemCoreClock / 2;
        }

        if (_ulFreq < 100)
        {
                usPrescaler = 10000 - 1;                                        /* 分频比 = 10000 */
                usPeriod =  (uiTIMxCLK / 10000) / _ulFreq  - 1;                /* 自动重装的值 */
        }
        else if (_ulFreq < 3000)
        {
                usPrescaler = 100 - 1;                                        /* 分频比 = 100 */
                usPeriod =  (uiTIMxCLK / 100) / _ulFreq  - 1;                /* 自动重装的值 */
        }
        else        /* 大于4K的频率,无需分频 */
        {
                usPrescaler = 0;                                        /* 分频比 = 1 */
                usPeriod = uiTIMxCLK / _ulFreq - 1;        /* 自动重装的值 */
        }

        /* Time base configuration */
        TIM_TimeBaseStructure.TIM_Period = usPeriod;
        TIM_TimeBaseStructure.TIM_Prescaler = usPrescaler;
        TIM_TimeBaseStructure.TIM_ClockDivision = 0;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0000;                /* TIM1 和 TIM8 必须设置 */        

        TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure);

        /* PWM1 Mode configuration: Channel1 */
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
        TIM_OCInitStructure.TIM_Pulse = (_ulDutyCycle * usPeriod) / 10000;
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
        
        TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;        /* only for TIM1 and TIM8. */        
        TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;                        /* only for TIM1 and TIM8. */               
        TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;                /* only for TIM1 and TIM8. */
        TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;                /* only for TIM1 and TIM8. */
        
        if (_ucChannel == 1)
        {
                TIM_OC1Init(TIMx, &TIM_OCInitStructure);
                TIM_OC1PreloadConfig(TIMx, TIM_OCPreload_Enable);
        }
        else if (_ucChannel == 2)
        {
                TIM_OC2Init(TIMx, &TIM_OCInitStructure);
                TIM_OC2PreloadConfig(TIMx, TIM_OCPreload_Enable);
        }
        else if (_ucChannel == 3)
        {
                TIM_OC3Init(TIMx, &TIM_OCInitStructure);
                TIM_OC3PreloadConfig(TIMx, TIM_OCPreload_Enable);
        }
        else if (_ucChannel == 4)
        {
                TIM_OC4Init(TIMx, &TIM_OCInitStructure);
                TIM_OC4PreloadConfig(TIMx, TIM_OCPreload_Enable);
        }

        TIM_ARRPreloadConfig(TIMx, ENABLE);

        /* TIMx enable counter */
        TIM_Cmd(TIMx, ENABLE);

        /* 下面这句话对于TIM1和TIM8是必须的,对于TIM2-TIM6则不必要 */
        if ((TIMx == TIM1) || (TIMx == TIM8))
        {
                TIM_CtrlPWMOutputs(TIMx, ENABLE);
        }
}

函数中略有瑕疵, /* 配置TIM定时更新中断 (Update) */后的处理有问题,一个是重复处理,这个不影响,一个是定时器与定时器中断没有对应上。
通过将不同定时器同一类别参数进行封装,在这两个函数中进行调用,使不同定时器的配置融合在同一个函数中,整齐统一而又互不干扰。
回复

使用道具 举报

14

主题

207

回帖

254

积分

高级会员

积分
254
 楼主| 发表于 2018-4-8 21:32:32 | 显示全部楼层
本帖最后由 龙之谷 于 2018-4-8 21:41 编辑

楼层bug,重复楼。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106738
QQ
发表于 2018-4-9 00:32:45 | 显示全部楼层
666
回复

使用道具 举报

95

主题

297

回帖

582

积分

金牌会员

123

积分
582
发表于 2018-8-27 16:57:01 | 显示全部楼层
龙之谷 发表于 2018-4-8 21:32
楼层bug,重复楼。

继续更新啊,等待关注龙之谷
回复

使用道具 举报

14

主题

207

回帖

254

积分

高级会员

积分
254
 楼主| 发表于 2018-8-29 10:04:21 | 显示全部楼层
ssssssss 发表于 2018-8-27 16:57
继续更新啊,等待关注龙之谷

哈哈,有些久了,还让你给翻出来了。最近刚换住处,新住处没有网络,刚买了U盘,准备再长些写些东西,最近这些天,感觉学习时间几近为零,有些空虚,希望自己能再坚持写上一波吧。共勉!
回复

使用道具 举报

95

主题

297

回帖

582

积分

金牌会员

123

积分
582
发表于 2018-8-29 11:19:22 | 显示全部楼层
龙之谷 发表于 2018-8-29 10:04
哈哈,有些久了,还让你给翻出来了。最近刚换住处,新住处没有网络,刚买了U盘,准备再长些写些东西,最 ...

最近也学习硬汉的东西,很牛的思路,希望一起学习,以后你发帖子我都会关注一下
回复

使用道具 举报

6

主题

33

回帖

51

积分

初级会员

积分
51
发表于 2019-4-6 10:04:35 | 显示全部楼层
龙之谷 发表于 2018-8-29 10:04
哈哈,有些久了,还让你给翻出来了。最近刚换住处,新住处没有网络,刚买了U盘,准备再长些写些东西,最 ...

楼主的思维导图画的不错,能否问一下用什么软件画的啊
回复

使用道具 举报

14

主题

207

回帖

254

积分

高级会员

积分
254
 楼主| 发表于 2019-4-8 09:35:33 | 显示全部楼层
大鹏 发表于 2019-4-6 10:04
楼主的思维导图画的不错,能否问一下用什么软件画的啊

软件名称是思维导图(Mindline)
回复

使用道具 举报

29

主题

514

回帖

606

积分

金牌会员

积分
606
QQ
发表于 2019-4-9 09:21:30 | 显示全部楼层
感谢分享思维导图软件。

昨天尝试用手机编辑doc文档,发现现在手机办公也可以做到很方便了。必须与时俱进!
Releasing your creativity
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-3 06:02 , Processed in 0.395539 second(s), 35 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表