本帖最后由 hejun96 于 2021-9-1 16:10 编辑
#申请原创# @21小跑堂
最近ST家的涨价潮和缺货潮下,国产选型越来越火爆,最近使用的一款是CX32L003 封装是TSSOP-20,可替代STM8S003F3 20 pin对应的型号,其资源分布和STM8S003的对比如附图,但STM8S003和CX32L003的引脚资源分配不一样,而CX32L003还是ARM Cortex M0的核,所以只能使用CX32L003推出的HAL库或者是CX32L003的寄存器操作了,下面会介绍两种操作方式。
对于任意的一款单片机,首当其冲的就是时钟,时钟作为单片机的心脏为其提供"心跳",决定了定时器的时钟周期和UART波特率的分频等。以下是CX32L003的时钟(附图配有时钟树):
外部高速RC时钟HIRC(4MHz)(默认主频)
外部低速晶振时钟LXT(32.768KHZ) ->一般可作为RTC的时钟使用
内部低速RC时钟LIRC(38.4KHz与32.768KHz可配置)
外部高速时钟HXT(4MHz~24MHz)
因为平时多用内部时钟,这里我们用HAL库根据例程配置下内部高速时钟24MHz作主频(时钟源初始化):
- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] System Clock Configuration
- * @retval None
- */
- void SystemClock_Config(void)
- {
-
- RCC_OscInitTypeDef RCC_OscInitStruct = {0};
- RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HIRC;
- RCC_OscInitStruct.HIRCState = RCC_HIRC_ON;
- RCC_OscInitStruct.HIRCCalibrationValue = RCC_HIRCCALIBRATION_24M;
- if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
- {
- Error_Handler();
- }
-
- /**Initializes the CPU, AHB and APB busses clocks
- */
- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK;
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HIRC;
- RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;
- RCC_ClkInitStruct.APBCLKDivider = RCC_PCLK_DIV1;
- if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct) != HAL_OK)
- {
- Error_Handler();
- }
- }
可以用GPIO初始化输出高低电平验证下,此处以LED为例 :
- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] Configures LED GPIO.
- * @param Led: Led to be configured.
- * This parameter can be one of the following values:
- * [url=home.php?mod=space&uid=2817080]@ARG[/url] LED1
- */
- void BSP_LED_Init(Led_TypeDef Led)
- {
- GPIO_InitTypeDef gpioinitstruct={0};
-
- /* Enable the GPIO_LED Clock */
- LEDx_GPIO_CLK_ENABLE(Led);
-
- /* Configure the GPIO_LED pin */
- gpioinitstruct.Pin = LED_PIN[Led];
- gpioinitstruct.Mode = GPIO_MODE_OUTPUT;
- gpioinitstruct.OpenDrain = GPIO_PUSHPULL;
- gpioinitstruct.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
- gpioinitstruct.SlewRate = GPIO_SLEW_RATE_HIGH;
- gpioinitstruct.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
- gpioinitstruct.Pull = GPIO_NOPULL;
- HAL_GPIO_Init(LED_PORT[Led], &gpioinitstruct);
-
- /* Reset PIN to switch off the LED */
- HAL_GPIO_WritePin(LED_PORT[Led],LED_PIN[Led], GPIO_PIN_RESET);
- }
用此处提供的函数可以方便验证
上面讲的是用HAL库的方式操作,下面和介绍下最近用寄存器操作的方式,如:pwm,uart
高级定时器TIM1由一个16位的自动装载计数器组成,它由一个可编程的预分频器驱动。他适合多种用途,包含测量输入信号的脉冲宽度(输入捕获),或者产生输出波形(输出比较、pwm、嵌入死区时间的互补pwm等)。其主要特性包括:
1.16位向上、向下、向上/向下自动装载计数器
2.16 位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为 1~65535 之间的任意数值
3. 多达 4 个独立通道:
输入捕获
输出比较
PWM 生成(边缘或中间对齐模式)
单脉冲模式输出
4.死区时间可编程的互补输出
5.使用外部信号控制定时器和定时器互联的同步电路
6.允许在指定数目的计数器周期之后更新定时器寄存器的重复计数器
7.刹车输入信号可以将定时器输出信号置于复位状态或者一个已知状态
8.如下事件发生时产生中断:
更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
输入捕获
输出比较
刹车信号输入
9.支持针对定位的增量(正交)编码器和霍尔传感器电路
10.触发输入作为外部时钟或者按周期的电流管理
PWM脉冲宽度调制模式可以产生一个由 TIM1_ARR 寄存器确定频率、由 TIM1_CCRx 寄存器确定占空比的信号。在 TIM1_CCMRx 寄存器中的 OCxM 位写入’110’(PWM 模式 1)或’111’(PWM 模式 2),能够独立地设置每个 OCx 输出通道产生一路 PWM。必须通过设置 TIM1_CCMRx 寄存器的 OCxPE 位使能相应的预装载寄存器,最后还要设置 TIM1_CR1 寄存器的 ARPE 位,(在向上计数或中心对称模式中)使能自动重装载的预装载寄存器。仅当发生一个更新事件的时候,预装载寄存器才能被传送到影子寄存器,因此在计数器开始计数之前,必须通过设置 TIM1_EGR 寄存器中的 UG 位来初始化所有的寄存器。OCx 的极性可以通过软件在 TIM1_CCER 寄存器中的 CCxP 位设置,它可以设置为高电平有效或低电平有效。OCx 的输出使能通过(TIM1_CCER 和 TIM1_BDTR 寄存器中)CCxE、CCxNE、MOE、OSSI 和 OSSR 位的组合控制。详见 TIM1_CCER 寄存器的描述。在 PWM 模式(模式 1 或模式 2)下,TIM1_CNT 和 TIM1_CCRx 始终在进行比较,(依据计数器的计数方向)以确定是否符合 TIM1_CCRx≤TIM1_CNT 或者 TIM1_CNT≤TIM1_CCRx。根据 TIM1_CR1寄存器中 CMS位的状态,定时器能够产生边沿对齐的 PWM 信号或中央对齐的PWM信号。使用高级定时器TIM1输出4路pwm的方式,复用的IO引脚是PC6(TIM1_CH1),PD2(TIM1_CH2),PC3(TIM1_CH3),PC4(TIM1_CH4)。
- RCC->HCLKEN |= 1 << 2;
- RCC->HCLKEN |= 1 << 3;
- RCC->PCLKEN |= 1 << 10;//RCC_TIM1
-
- GPIOC->AFR |= 0X01000000;//TIM1_CH1
- GPIOC->DIRCR |= 1 << 6;//pc6
- GPIOC->OTYPER &= ~(1 << 6);
- ///GPIOC->PUPDR |= 2 << 12;
- GPIOC->SLEWCR &= ~(1 << 6);
-
-
- GPIOD->AFR |= 0X00000100;//TIM1_CH2
- GPIOD->DIRCR |= 1 << 2;//PD2
- GPIOD->OTYPER &= ~(1 << 2);
- ///GPIOD->PUPDR |= 2 << 4;
- GPIOD->SLEWCR &= ~(1 << 2);
-
-
- GPIOC->AFR |= 0X00001000;//TIM3_CH1
- GPIOC->DIRCR |= 1 << 3;//PC3
- GPIOC->OTYPER &= ~(1 << 3);
- ///GPIOC->PUPDR |= 2 << 6;
- GPIOC->SLEWCR &= ~(1 << 3);
-
- GPIOC->AFR |= 0X00010000;//TIM4_CH1
- GPIOC->DIRCR |= 1 << 4;//PC4
- GPIOC->OTYPER &= ~(1 << 4);
- ///GPIOC->PUPDR |= 2 << 8;
- GPIOC->SLEWCR &= ~(1 << 4);
-
- TIM1->ARR = arr;
- TIM1->PSC = psc;
-
- TIM1->CCMR1 |= 6 << 4;//TIM1_CH1 OC_MODE1
- TIM1->CCMR1 |= 1 << 3;//OC_MODE1 enable
-
- TIM1->CCMR1 |= 6 << 12;//TIM1_CH2 OC_MODE1
- TIM1->CCMR1 |= 1 << 11;//OC_MODE2 enable
-
- TIM1->CCMR2 |= 6 << 4;//TIM1_CH3 OC_MODE1
- TIM1->CCMR2 |= 1 << 3;//OC_MODE3 enable
-
- TIM1->CCMR2 |= 6 << 12;//TIM1_CH4 OC_MODE1
- TIM1->CCMR2 |= 1 << 11;//OC_MODE4 enable
- /*
- TIM1->CR1 |= 1<<7;//TIM1 ARP1 enable
- TIM1->CR1 |= 1<<4;//TIM1 计数器向下计数
- */
- TIM1->CCER |= 1 << 0;//OC1 enable
- TIM1->CCER |= 1 << 4;//OC2 enable
- TIM1->CCER |= 1 << 8;//OC3 enable
- TIM1->CCER |= 1 << 12;//OC4 enable
-
- TIM1->CCR1 = TIM1_CH1_PULSEWIDTH;
- TIM1->CCR2 = TIM1_CH2_PULSEWIDTH;
- TIM1->CCR3 = TIM1_CH3_PULSEWIDTH;
- TIM1->CCR4 = TIM1_CH4_PULSEWIDTH;
-
- TIM1->BDTR |= 1 << 15;
-
- ///TIM1->CR1 = 0x0080;//ARPE enable
-
- TIM1->CR1 |= 1 << 0;//TIM1 enable
这里代码使用的是寄存器的方式输出pwm,首先要打开的是RCC的时钟,也就是RCC->HCLKEN的寄存器,根据参考手册,bit0 表示GPIOA,bit1 表示 GPIOB 的时钟,bit2表示GPIOC的时钟,bit3表示GPIOD的时钟 1表示使能,0表示关闭。TIM1主要是用到了CCR,CCMR和CCER寄存器.CCMR寄存器使能对应的预装载和快速使能;CCER寄存器输出使能。CCR寄存器是pwm输出的通道值。
再如用UART0中断收发,使用的是CX32L003 的PA1(UART0_RX) 和PA2(UART0_TX) :
使用CX32L003的项目是灯带调光的智能家居项目,配合涂鸦模组使用手机app控制开关并调节色温和亮度,如图所示:
使用了6路pwm分别调节灯带几个通道的亮度和色温,色温分冷色和暖色,pwm越大则暖色光向冷色渐变,反之则向暖色光渐变;而亮度则是由pwm输出控制亮暗的程度。pwm越大则亮度越亮,而CX32L003 64k flash 4k SRAM,比较适合做这种小型应用。
|