[RISC-V MCU 创新应用比赛] 基于CH32V307天然色素提取工艺改进

[复制链接]
1412|0
 楼主| zeshoufx 发表于 2023-2-28 11:04 | 显示全部楼层 |阅读模式
本帖最后由 zeshoufx 于 2023-3-3 20:45 编辑

基于CH32V307天然色素提取工艺改进
1、天然色素及提取
天然色素(NaturalPigments)的开发与应用己成为各行业科技工作者普遍关注的课题。人们试图从各种动植物资源中获取天然色素,同时探索其生理活性,来缓解并解决由合成色素所带来的各种问题。但是由于天然色素色泽不稳定,在其使用过程中容易受各种因素(如光照、温度、氧化、pH值、介质极性、金属离子、添加剂等)的影响而发生褪色、变色等方面的变化,而影响其着色效果,严重制约了天然色素代替人工合成色素的进程。现代天然植物色素的提取方法可分为溶剂提取法、熬煮法、酶反应法、超临界萃取法、压榨法、粉碎等方法。植物色素提取设备现场如图1所示。                                                                      5774063fd89c1e4243.png
1植物色素提取设备现场
2、天然色素提取工艺特点及关键技术
天然色素提取,现场采用的方法是萃取提取,在各储料罐顶部需要进料、进水、进酒精,底部需要出料,包括最终的色素、水,其中酒精可能需要重复使用。因此储料罐链接的各个管道及阀门需要合理的控制,在保证质量的前提下,节约用料也是重点考量的一个要素。
目前现场工艺的主要特点包括1、各种加料工程全部是人工完成,有经验的工人来完成调节阀门,期间不定时通过观察窗查看现场各步骤结果;2、出料品质由人工观察提取,并送研究院化验,取样和化验周期长,很难获取符合标准质量的色素;3、部分色素需人工品尝后来决定其品质,主观因素影响较大。
关键技术:通过开发一种识别色素特征的终端设备,将特征参数识别出来后发送到后台,后台系统通过标定,并与研究院化验数据进行对比,PLC控制系统根据终端设备的数据,控制管道阀门的开关,同时控制储料罐温度和气压。
3、原理实现
现场设备主要提取6种天然植物色素,现场每种色素的颜色差别较大,并且同一种色素在每个工艺过程中,颜色差别也较大。因此可以通过识别不同工艺下的色素颜色RGB分量,通过标定在不同RGB分量值下,对应研究院化验的结果,可得到各色素质量较好且经济的控制。现场的现场胡萝卜素在两个工艺下的颜色如图2所示。

8420163fd89dc41eb8.jpg     8680163fd8f095454c.jpg
file:///C:/Users/zes/AppData/Local/Temp/ksohtml156/wps3.png
2 胡萝卜素在两个工艺下的颜色
4、硬件设计及传感器
样机硬件采用CH32V307VC单片机,小批量量产采用CH32V303CB单片机和ARM单片机GD32F303CC,这里主要以CH32V307VC开发板效果介绍。样机硬件和量产硬件如图3所示。
file:///C:/Users/zes/AppData/Local/Temp/ksohtml156/wps4.png 3696863fdd8e7bcebd.jpg       9684463fdd90579089.jpg file:///C:/Users/zes/AppData/Local/Temp/ksohtml156/wps5.png
                      图3 a量产硬件                                                                                                                               图3 b样机硬件(基于开发板)
其中主要的颜色识别传感器为欧姆龙的B5WC系列,价格1200RMB左右,采用IIC协议进行通信。B5WC型设备内置专用颜色传感器由装载了PD(光电二极管)来检测以具有可见光宽波长区域的白色LED为光源、以红:Red、绿:Green、蓝:Blue共三种光原色为受光元件的各波长区域光的RGB光电IC、光学透镜、装载了MCU的内部电路等专用元件构成。此外,即使检测距离发生变化,RGB比率也几乎保持不变状态,这也是颜色传感器的另一大特色。以下表示检测距离发生变化时的颜色传感器的受光输出、以及受光输出比率。颜色传感器也是一种反射型传感器,所以RGB受光输出值也会根据检测距离的变化而发生变化,但RGB受光输出比率几乎不变。这是因为除了检测物体的反射光量以外,还会检测反射光中所含R/G/B各波长成分所致。因此,即使与检测物体的间距各异并发生变化,也可稳定辨别检测物体的色差。传感器实物图及与单片机连接分别如图4和图5所示。
                                                                                 1265063fd7069ccb2c.png
file:///C:/Users/zes/AppData/Local/Temp/ksohtml156/wps6.png
4 B5WC传感器实物图
5235863fd7084aeda3.png
file:///C:/Users/zes/AppData/Local/Temp/ksohtml156/wps7.jpg
5 B5WC传感器与单片机连接图
5、关键代码
1310263fd892dc63ed.png
5.1 B5WC传感器驱动
file:///C:/Users/zes/AppData/Local/Temp/ksohtml156/wps8.jpg
  1. /*
  2. * b5wc.c
  3. *
  4. *  Created on: Jan 30, 2023
  5. *      Author: zeshou
  6. */
  7. #include "b5wc.h"

  8. #define Address_Lenth    Address_8bit

  9. void b5wc_io_set(void)
  10. {
  11.     GPIO_InitTypeDef GPIO_InitStructure = {0};
  12.     I2C_InitTypeDef  I2C_InitTSturcture = {0};

  13.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  14.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);

  15.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  16.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
  17.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  18.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  19.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  20.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
  21.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  22.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  23.     I2C_InitTSturcture.I2C_ClockSpeed = 100000;
  24.     I2C_InitTSturcture.I2C_Mode = I2C_Mode_I2C;
  25.     I2C_InitTSturcture.I2C_DutyCycle = I2C_DutyCycle_2;
  26.     I2C_InitTSturcture.I2C_OwnAddress1 = 0x80;
  27.     I2C_InitTSturcture.I2C_Ack = I2C_Ack_Enable;
  28.     I2C_InitTSturcture.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  29.     I2C_Init(I2C2, &I2C_InitTSturcture);

  30.     I2C_Cmd(I2C2, ENABLE);

  31.     I2C_AcknowledgeConfig(I2C2, ENABLE);
  32. }

  33. void b5wc_write_byte(u16 addr,u8 data)
  34. {
  35.     while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY) != RESET);
  36.     I2C_GenerateSTART(I2C2, ENABLE);

  37.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
  38.     I2C_Send7bitAddress(I2C2, 0X80, I2C_Direction_Transmitter);

  39.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  40.     #if(Address_Lenth == Address_8bit)
  41.         I2C_SendData(I2C2, (u8)(addr & 0x00FF));
  42.         while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  43.     #elif(Address_Lenth == Address_16bit)
  44.         I2C_SendData(I2C2, (u8)(WriteAddr >> 8));
  45.         while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  46.         I2C_SendData(I2C2, (u8)(WriteAddr & 0x00FF));
  47.         while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  48.     #endif

  49.         if(I2C_GetFlagStatus(I2C2, I2C_FLAG_TXE) != RESET)
  50.         {
  51.             I2C_SendData(I2C2, data);
  52.         }

  53.         while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
  54.         I2C_GenerateSTOP(I2C2, ENABLE);
  55. }

  56. //void b5wc_wait_standby_state(void)
  57. //{
  58. //    vu32 val = 0;
  59. //
  60. //    while(1)
  61. //    {
  62. //        while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY));
  63. //        i2c_start_on_bus(I2C0);
  64. //        while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND));
  65. //        i2c_master_addressing(I2C0, 0x80, I2C_TRANSMITTER);
  66. //
  67. //        do
  68. //        {
  69. //            val = I2C_STAT0(I2C0);
  70. //
  71. //        }while(0 == (val & (I2C_STAT0_ADDSEND | I2C_STAT0_AERR)));
  72. //
  73. //        if(val & I2C_STAT0_ADDSEND)
  74. //        {
  75. //            i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);
  76. //            i2c_stop_on_bus(I2C0);
  77. //            return ;
  78. //
  79. //        }
  80. //        else
  81. //        {
  82. //            i2c_flag_clear(I2C0,I2C_FLAG_AERR);
  83. //        }
  84. //        i2c_stop_on_bus(I2C0);
  85. //        while(I2C_CTL0(I2C0)&0x0200);
  86. //    }
  87. //}

  88. u8 b5wc_read_byte(u16 addr)
  89. {
  90.     u8 temp = 0;

  91.     while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY) != RESET);
  92.     I2C_GenerateSTART(I2C2, ENABLE);

  93.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
  94.     I2C_Send7bitAddress(I2C2, 0x80, I2C_Direction_Transmitter);

  95.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  96.     #if(Address_Lenth == Address_8bit)
  97.         I2C_SendData(I2C2, (u8)(addr & 0x00FF));
  98.         while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  99.     #elif(Address_Lenth == Address_16bit)
  100.         I2C_SendData(I2C2, (u8)(ReadAddr >> 8));
  101.         while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  102.         I2C_SendData(I2C2, (u8)(ReadAddr & 0x00FF));
  103.         while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  104.     #endif

  105.         I2C_GenerateSTART(I2C2, ENABLE);

  106.         while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
  107.         I2C_Send7bitAddress(I2C2, 0x80, I2C_Direction_Receiver);

  108.         while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
  109.         while(I2C_GetFlagStatus(I2C2, I2C_FLAG_RXNE) == RESET)
  110.             I2C_AcknowledgeConfig(I2C2, DISABLE);

  111.         temp = I2C_ReceiveData(I2C2);
  112.         I2C_GenerateSTOP(I2C2, ENABLE);

  113.         return temp;
  114. }

  115. void b5cw_init(void)
  116. {
  117.     b5wc_io_set();
  118.     Delay_Ms(100);

  119.     b5wc_write_byte(0x00,0x5a);

  120.     b5wc_write_byte(0x01,0x0a);

  121.     b5wc_write_byte(0x00,0x5b);

  122.     if(0x0a==b5wc_read_byte(0x01))
  123.     {
  124.         printf("参数设置成功...\r\n");
  125.     }
  126.     else
  127.     {
  128.         printf("参数设置失败...\r\n");
  129.     }
  130. }

  131. void b5cw_RGB_value_get(u16 *rgb)
  132. {
  133.     u8 temp1=0,temp2=0,temp3=0,temp4=0,temp5=0,temp6=0;

  134.     temp1=b5wc_read_byte(0x02);
  135.     temp2=b5wc_read_byte(0x03);

  136.     temp3=b5wc_read_byte(0x04);
  137.     temp4=b5wc_read_byte(0x05);

  138.     temp5=b5wc_read_byte(0x06);
  139.     temp6=b5wc_read_byte(0x07);

  140.     rgb[0]=(temp2<<8)+temp1;
  141.     rgb[1]=(temp4<<8)+temp3;
  142.     rgb[2]=(temp6<<8)+temp5;
  143. }





5.2 Modbus-RTU协议实现


  1. #include "tim3.h"
  2. #include "Sys_Config.h"
  3. #if MD_USD_SALVE
  4. //#include "MDS_RTU_Serial.h"
  5. #include "MDS_RTU_Serial_1.h"
  6. #else
  7. #include "MDM_RTU_Serial.h"
  8. #endif

  9. vu32 sys_tick_100us=0;

  10. //General purpose timer 3 interrupt initialization
  11. //The clock here is 2 times that of APB1, and APB1 is 36M
  12. //arr: automatic reload value.
  13. //psc: clock prescaler number
  14. //Timer 3 is used here!
  15. void TIM3_Int_Init(u16 arr,u16 psc)
  16. {
  17.     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  18.         NVIC_InitTypeDef NVIC_InitStructure;

  19.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

  20.         TIM_TimeBaseStructure.TIM_Period = arr;
  21.         TIM_TimeBaseStructure.TIM_Prescaler =psc;
  22.         TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  23.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  24.         TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

  25.         TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE );

  26.         NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
  27.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  28.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
  29.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  30.         NVIC_Init(&NVIC_InitStructure);

  31.         TIM_Cmd(TIM3, ENABLE);
  32. }

  33. void TIM3_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
  34. void TIM3_IRQHandler(void)
  35. {
  36.     if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
  37.     {
  38.         TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
  39.         sys_tick_100us++;
  40.         #if !MD_RTU_USED_OS
  41.             #if MD_USD_SALVE
  42. //          MDSTimeHandler100US(sys_tick_100us);
  43.             MDSTimeHandler100US_1(sys_tick_100us);
  44.             #else
  45.             MDMTimeHandler100US(sys_tick_100us);
  46.             #endif
  47.         #endif
  48.     }
  49. }
  1. #include "usart3.h"
  2. #include "Sys_Config.h"
  3. #if MD_USD_SALVE
  4. #include "MDS_RTU_Serial_1.h"
  5. #else
  6. #include "MDM_RTU_Serial.h"
  7. #include "MD_RTU_SysInterface.h"
  8. #include "MDM_RTU_Fun.h"
  9. #endif

  10. void RS485RWConvInit(void)
  11. {
  12. //        GPIO_InitTypeDef  GPIO_InitStructure;
  13. //        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC| RCC_APB2Periph_AFIO, ENABLE);
  14. //        BKP_TamperPinCmd(DISABLE);
  15. //        BKP_ITConfig(DISABLE);  

  16. //        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
  17. //        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  18. //        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  19. //        GPIO_Init(GPIOC, &GPIO_InitStructure);
  20. //        GPIO_ResetBits(GPIOC,GPIO_Pin_13);

  21. }


  22. void init_usart3(u32 baudRate)
  23. {
  24.     USART_InitTypeDef USART_InitStructure;
  25.         GPIO_InitTypeDef GPIO_InitStructure;
  26.         NVIC_InitTypeDef NVIC_InitStruct;
  27.         /* Enable GPIO clock */
  28.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 |\
  29.                 RCC_APB2Periph_GPIOA, ENABLE);

  30.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  31.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  32.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  33.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  34.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  35.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  36.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  37.         GPIO_Init(GPIOA, &GPIO_InitStructure);

  38.         USART_InitStructure.USART_BaudRate = baudRate;
  39.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  40.         USART_InitStructure.USART_StopBits = USART_StopBits_1;
  41.         USART_InitStructure.USART_Parity = USART_Parity_No;
  42.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  43.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  44.      /* Configure USARTz */
  45.         USART_Init(USART1, &USART_InitStructure);
  46.         USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
  47.         USART_Cmd(USART1, ENABLE);


  48.         NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn;
  49.         NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
  50.         NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;
  51.         NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;
  52.         NVIC_Init(&NVIC_InitStruct);
  53. }
  54. void usart3_send_byte(u8 byte)
  55. {
  56.     while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET);
  57.         USART_SendData(USART1,byte);
  58.         while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET);
  59. }
  60. void usart3_send_bytes(u8 *bytes,int len)
  61. {
  62.         int i;
  63.         for(i=0;i<len;i++)
  64.         {
  65.                 usart3_send_byte(bytes[i]);
  66.         }
  67. }
  68. void usart3_send_string(char *string)
  69. {
  70.         while(*string)
  71.         {
  72.                 usart3_send_byte(*string++);
  73.         }
  74. }


  75. void USART1_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
  76. void USART1_IRQHandler(void)
  77. {
  78.     if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
  79.         {
  80.                         uint8_t data = USART_ReceiveData(USART1);
  81.                         #if !MD_RTU_USED_OS
  82.                                 #if MD_USD_SALVE
  83.                                         MDSSerialRecvByte_1(data);
  84.                                 #else
  85.                                         #if MDM_USD_USART3
  86.                                                 MDMSerialRecvByte(data);
  87.                                         #endif
  88.                                 #endif
  89.                         #else
  90.                                 extern Modbus_RTU modbus_RTU;
  91.                                 MD_RTU_MsgPut((PModbusBase)(&modbus_RTU), MD_RTU_MSG_HANDLE_ARG(&modbus_RTU),(void*)(data),0);
  92.                         #endif
  93.     }
  94. }



6、识别效果及展示视频
                             
                                     984963fd70a7ca5bf.png                                            识别效果
6748863fdd1b17a32b.jpg

file:///C:/Users/zes/AppData/Local/Temp/ksohtml156/wps9.jpg
视频链接:
https://www.bilibili.com/video/BV1aG4y1U7fo/?spm_id_from=333.999.list.card_archive.click
天然色———胡萝卜素提取_哔哩哔哩_bilibili
开源网址:https://gitee.com/zhang_en/color_identify.git

7、现场应用效果及前景
目前已装上,通过终端模块连接4G DTU,传输到后台数据库,采集原始样本并形成规模数据后与研究院沟通。 73966401e7b1b686f.png 34246401e80fe658c.png
624306401e8507b1ad.png
222166401ebc6eac03.png
888946401ebd208362.png
云南享有动植物王国,天然植物色素丰富,集团内部下属公司多是生物医药,相同的工艺环节甚多,推广前景很好。另外化工、喷漆等行业也是潜在的应用行业。


567606401e7e649a8e.png
118306401e830adafb.png
您需要登录后才可以回帖 登录 | 注册

本版积分规则

67

主题

1991

帖子

15

粉丝
快速回复 在线客服 返回列表 返回顶部