完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
` 本帖最后由 MMCU5721167 于 2020-1-15 14:08 编辑 随着现代工业生产向高速化、自动化方向的发展,生产过程中长期以来由人眼起主导作用的颜色识别工作将越来越多地被相应的颜色传感器所替代。例如:图书馆使用颜色区分对文献进行分类,能够极大地提高排架管理和统计等工作;在包装行业,产生包装利用不同的颜色和装潢来表示其不同的性质或用途;在物流运输过程中通过识别颜色来区分不同的货物,通过颜色判断货物的不同属性。 颜色检测模块能在一定的范围内检测和测量几乎所有的可见光,内置的振荡器会输出方波,通过MM32 MCU的输入捕获功能来检测外部事件或者输入信号,当外部事件发生或者信号发生变化时,在指定的输入捕获引脚上发生了一个指定的延跳变(可以设置上升沿、下降沿或者双边沿)。定时器捕获到特定的延跳变后,把计数寄存器当前的值锁存到通道寄存器中。 高级定时器tiM1和通用定时器TIM23各有4个捕获比较通道,基本定时器TIM141617各有一个捕获比较通道。 通过配置TIM的输入捕获方式,可以准确的得到输入信号的脉冲宽度,从而计算出信号的频率和占空比等信息。 TIM输入捕捉模式 在输入捕获模式下,当检测到ICx 信号上相应的边沿后,计数器的当前值被锁存到捕获/比较寄存器(TIMx_CCRx)中。当发生捕获事件时,相应的CCxIF 标志(TIMx_SR 寄存器)被置‗1‘,如果开放了中断或者DMA 操作,则将产生中断或者DMA 请求。如果发生捕获事件时CCxIF 标志已经为高,那么重复捕获标志CCxOF(TIMx_SR 寄存器)被置1。写CCxIF = 0 可清除CCxIF,或读取存储在TIMx_CCRx 寄存器中的捕获数据也可清除CCxIF。写CCxOF = 0 可清除CCxOF。 以下例子说明如何在TI1 输入的上升沿时捕获计数器的值到TIMx_CCR1 寄存器中。 配置步骤: 1) 选择有效输入端:TIMx_CCR1 必须连接到TI1 输入,所以写入TIMx_CCMR1寄存器中的CC1S =01,一旦CC1S 不为00 时,通道被配置为输入,并且TIMx_CCR1 寄存器变为只读。 2) 根据输入信号的特点,配置输入滤波器为所需的带宽(即输入为TIx 时,输入滤波器控制位是TIMx_CCMRx 寄存器中的ICxF 位)。假设输入信号在最多5 个时钟周期的时间内抖动,我们须配置滤波器的带宽长于5 个时钟周期;因此我们可以(以fDTS 频率)连续采样8 次,以确认在TI1 上一次真实的边沿变换,即在TIMx_CCMR1 寄存器中写入IC1F = 0011。 3) 选择TI1 通道的有效转换边沿,在TIMx_CCER 寄存器中写入CC1P = 0(上升沿)。 4) 配置输入预分频器。在本例中,我们希望捕获发生在每一个有效的电平转换时刻,因此预分频器被禁止(写TIMx_CCMR1寄存器的IC1PS=00)。 5) 设置TIMx_CCER 寄存器的CC1E = 1,允许捕获计数器的值到捕获寄存器中。 6) 如果需要,通过设置TIMx_DIER 寄存器中的CC1IE 位允许相关中断请求,通过设置TIMx_DIER寄存器中的CC1DE 位允许DMA 请求。 当发生一个输入捕获时: 1) 当产生有效的电平转换时,计数器的值被传送到TIMx_CCR1 寄存器。 2) CC1IF 标志被设置(中断标志)。当发生至少2 个连续的捕获时,而CC1IF 未曾被清除,CC1OF也被置1。 3) 如设置了CC1IE 位,则会产生一个中断。 4) 如设置了CC1DE 位,则还会产生一个DMA 请求。 为了处理捕获溢出,建议在读出捕获溢出标志之前读取数据,这是为了避免丢失在读出捕获溢出标志之后和读取数据之前可能产生的捕获溢出信息。 注:设置TIMx_EGR 寄存器中相应的CCxG 位,可以通过软件产生输入捕获中断和/或DMA 请求。 下面以TIM1_CH1为例,配置输入捕获模式。 void TIM1_PWMINPUT_INIT(u32 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; TIM_ICInitTypeDef TIM1_ICInitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); //使能时钟 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_2);//PA8复用为TIM1_CH1 TIM_TimeBaseStructure.TIM_Period = arr; //自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数 TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn; NVIC_InitStructure.NVIC_IRQChannelPriority = 1; /*配置中断优先级*/ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); //CC1 通道被配置为输入,IC1 映射在TI1 上 TIM1_ICInitStructure.TIM_Channel = TIM_Channel_1; TIM1_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; TIM1_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; TIM1_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM1_ICInitStructure.TIM_ICFilter = 0x0; TIM_ICInit(TIM1, &TIM1_ICInitStructure); TIM_SelectInputTrigger(TIM1, TIM_TS_TI1FP1); //选择有效输入端 TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset); //配置为主从复位模式 TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE); //中断配置 TIM_ClearITPendingBit(TIM1, TIM_IT_CC1); //清除中断标志位 TIM_Cmd(TIM1, ENABLE); } 图1 复位模式 这样配置完成,TIM1进入复位模式。如图1,每当一个上升沿到来时,通道1将把计数值储存在TIM1->CCR1中,并重新初始化计数器,产生一个更新寄存器的信号。同时程序进入TIM1_CC中断,可以如下配置中断函数,来记录得到的数据。 void TIM1_CC_IRQHandler(void) { if((TIM1CH1_CAPTURE_STA & 0x80) == 0) //判断捕获标志为0 { TIM1CH1_CAPTURE_Period = TIM1->CCR1; TIM1CH1_CAPTURE_STA |= 0x80; } TIM_ClearITPendingBit(TIM1, TIM_IT_CC1); //清除中断标志位 } 下面,我们用一个颜色检测模组来介绍一下TIM1_CH1输入捕获的应用: 图2 YL-64 颜色检测模块应用 颜色检测模块能在一定的范围内检测和测量几乎所有的可见光,内置的振荡器会输出方波,通过S2和S3引脚来选择滤波器模式,引脚S0和S1选择方波与内置振荡器的比例。 下面是测试使用的程序 main函数 int main(void) { u32 RGB[3] = {0, 0, 0}; Uart_ConfigInit(9600); UartSendGroup((u8 *)printBuf, sprintf(printBuf, "sprintf ok ")); TIM1_PWMINPUT_INIT(0xffffffff, 0); delay_init(); GPIO_Config(); SetSensorFilter(FilterClear); SetSensorClock(ClockOFF); FilterSampleTime = 1000; //500ms per Color SetSensorClock(Clock100); WhiteBalance(); while (1) { GetRGBValue(RGB); UartSendGroup((u8 *)printBuf, sprintf(printBuf, "R=%d,G=%d,B=%d ", RGB[0], RGB[1], RGB[2])); delay_ms(1000); } } 模块的操作 void GetRGBValue(u32 *RGBArray) //与标准值对比,计算RGB值 { RGBArray[0] = GetColorValue(FilteRed) * 255 / WBArray[0]; RGBArray[1] = GetColorValue(FilteGreen) * 255 / WBArray[1]; RGBArray[2] = GetColorValue(FilteBlue) * 255 / WBArray[2]; } void HSI_SYSCLK(void) { RCC_HSICmd(ENABLE); while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET) ; RCC->CFGR &= ~0xf; while ((RCC->CFGR & 0xf) != 0x0); } void GPIO_Config() { NVIC_InitTypeDef NVIC_InitSturcture; EXTI_InitTypeDef EXTI_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //外部中断,需要使能AFIO时钟 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_Init(GPIOA, &GPIO_InitStructure); SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0); EXTI_InitStructure.EXTI_Line = EXTI_Line1; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_Init(&EXTI_InitStructure); NVIC_InitSturcture.NVIC_IRQChannel = EXTI0_1_IRQn; NVIC_InitSturcture.NVIC_IRQChannelCmd = ENABLE; NVIC_InitSturcture.NVIC_IRQChannelPriority = 0; NVIC_Init(&NVIC_InitSturcture); } //手动进行白平衡校准 void EXTI0_1_IRQHandler(void) { WhiteBalance(); EXTI_ClearITPendingBit(EXTI_Line1); } void WhiteBalance() { WBArray[0] = GetColorValue(FilteRed); WBArray[1] = GetColorValue(FilteGreen); WBArray[2] = GetColorValue(FilteBlue); } u32 GetColorValue(u8 Filter) { SetSensorFilter(Filter); delay_ms(20); //延时,等待波形稳定 TIM1CH1_CAPTURE_STA = 0; //清除捕获标志 while (1) { if (TIM1CH1_CAPTURE_STA & 0X80) break; } SensorCount = 48000000 / TIM1CH1_CAPTURE_Period; //频率 return SensorCount; } void SetSensorFilter(u8 Filter) { GPIOA->ODR &= ~(0x3 << 6); GPIOA->ODR |= Filter << 6; } void SetSensorClock(u8 Clock) { GPIOA->ODR &= ~(0x3 << 4); GPIOA->ODR |= Clock << 4; } 程序开始运行时会进行一次白平衡校准,因此我们需要将一个白色物体放在模块前方1CM处,运行程序,校准完成后,移开白色物体,再将一个红色物体放在模块前方,可以看到UART输出如下 |
|
相关推荐
|
|
只有小组成员才能发言,加入小组>>
2249个成员聚集在这个小组
加入小组灵动微电子MM32全系列MCU产品应用手册,库函数和例程和选型表
11703 浏览 3 评论
【MM32 eMiniBoard试用连载】+基于OLED12864的GUI---U8G2
5930 浏览 1 评论
【MM32 eMiniBoard试用连载】移植RT-Thread至MM32L373PS
10965 浏览 0 评论
【MM32 eMiniBoard测评报告】+ 开箱 + 初探
4577 浏览 1 评论
灵动微课堂(第106讲) | MM32 USB功能学习笔记 —— WinUSB设备
4302 浏览 1 评论
[MM32软件] MM32F002使用内部flash存储数据怎么操作?
982浏览 1评论
807浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-28 02:24 , Processed in 0.503884 second(s), Total 40, Slave 32 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号