一、项目主要是提取色素中RGB三个分量的值,主要运用在
医药、化工、生物科学邻域,通过识别颜色,颜色的深浅对应着色素的浓度,通过单片机获取颜色RGB分量,上传给后台系统(PLC或者DCS),根据工艺要求将原料阀门打开或者关闭。
二、主控制器采用CH32V307,之前参与RISC-V比赛所申请的,
程序包括:
1、颜色识别传感器驱动:
#include "b5wc.h"
#define Address_Lenth Address_8bit
void b5wc_io_set(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
I2C_InitTypeDef I2C_InitTSturcture = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
I2C_InitTSturcture.I2C_ClockSpeed = 100000;
I2C_InitTSturcture.I2C_Mode = I2C_Mode_I2C;
I2C_InitTSturcture.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitTSturcture.I2C_OwnAddress1 = 0x80;
I2C_InitTSturcture.I2C_Ack = I2C_Ack_Enable;
I2C_InitTSturcture.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C2, &I2C_InitTSturcture);
I2C_Cmd(I2C2, ENABLE);
I2C_AcknowledgeConfig(I2C2, ENABLE);
}
void b5wc_write_byte(u16 addr,u8 data)
{
while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY) != RESET);
I2C_GenerateSTART(I2C2, ENABLE);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C2, 0X80, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
#if(Address_Lenth == Address_8bit)
I2C_SendData(I2C2, (u8)(addr & 0x00FF));
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
#elif(Address_Lenth == Address_16bit)
I2C_SendData(I2C2, (u8)(WriteAddr >> 8));
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_SendData(I2C2, (u8)(WriteAddr & 0x00FF));
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
#endif
if(I2C_GetFlagStatus(I2C2, I2C_FLAG_TXE) != RESET)
{
I2C_SendData(I2C2, data);
}
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(I2C2, ENABLE);
}
u8 b5wc_read_byte(u16 addr)
{
u8 temp = 0;
while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY) != RESET);
I2C_GenerateSTART(I2C2, ENABLE);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C2, 0x80, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
#if(Address_Lenth == Address_8bit)
I2C_SendData(I2C2, (u8)(addr & 0x00FF));
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
#elif(Address_Lenth == Address_16bit)
I2C_SendData(I2C2, (u8)(ReadAddr >> 8));
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_SendData(I2C2, (u8)(ReadAddr & 0x00FF));
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
#endif
I2C_GenerateSTART(I2C2, ENABLE);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C2, 0x80, I2C_Direction_Receiver);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
while(I2C_GetFlagStatus(I2C2, I2C_FLAG_RXNE) == RESET)
I2C_AcknowledgeConfig(I2C2, DISABLE);
temp = I2C_ReceiveData(I2C2);
I2C_GenerateSTOP(I2C2, ENABLE);
return temp;
}
void b5cw_init(void)
{
b5wc_io_set();
Delay_Ms(100);
b5wc_write_byte(0x00,0x5a);
b5wc_write_byte(0x01,0x0a);
b5wc_write_byte(0x00,0x5b);
if(0x0a==b5wc_read_byte(0x01))
{
printf("参数设置成功...\r\n");
}
else
{
printf("参数设置失败...\r\n");
}
}
void b5cw_RGB_value_get(u16 *rgb)
{
u8 temp1=0,temp2=0,temp3=0,temp4=0,temp5=0,temp6=0;
temp1=b5wc_read_byte(0x02);
temp2=b5wc_read_byte(0x03);
temp3=b5wc_read_byte(0x04);
temp4=b5wc_read_byte(0x05);
temp5=b5wc_read_byte(0x06);
temp6=b5wc_read_byte(0x07);
rgb[0]=(temp2<<8)+temp1;
rgb[1]=(temp4<<8)+temp3;
rgb[2]=(temp6<<8)+temp5;
}
2、Modbus-RTU开发:
#include "tim3.h"
#include "Sys_Config.h"
#if MD_USD_SALVE
#include "MDS_RTU_Serial_1.h"
#else
#include "MDM_RTU_Serial.h"
#endif
vu32 sys_tick_100us=0;
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler =psc;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE );
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM3, ENABLE);
}
void TIM3_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
sys_tick_100us++;
#if !MD_RTU_USED_OS
#if MD_USD_SALVE
MDSTimeHandler100US_1(sys_tick_100us);
#else
MDMTimeHandler100US(sys_tick_100us);
#endif
#endif
}
}
#include "usart3.h"
#include "Sys_Config.h"
#if MD_USD_SALVE
#include "MDS_RTU_Serial_1.h"
#else
#include "MDM_RTU_Serial.h"
#include "MD_RTU_SysInterface.h"
#include "MDM_RTU_Fun.h"
#endif
void RS485RWConvInit(void)
{
}
void init_usart3(u32 baudRate)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 |\
RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = baudRate;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1, ENABLE);
NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;
NVIC_Init(&NVIC_InitStruct);
}
void usart3_send_byte(u8 byte)
{
while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET);
USART_SendData(USART1,byte);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET);
}
void usart3_send_bytes(u8 *bytes,int len)
{
int i;
for(i=0;i<len;i++)
{
usart3_send_byte(bytes[i]);
}
}
void usart3_send_string(char *string)
{
while(*string)
{
usart3_send_byte(*string++);
}
}
void USART1_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void USART1_IRQHandler(void)
{
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
uint8_t data = USART_ReceiveData(USART1);
#if !MD_RTU_USED_OS
#if MD_USD_SALVE
MDSSerialRecvByte_1(data);
#else
#if MDM_USD_USART3
MDMSerialRecvByte(data);
#endif
#endif
#else
extern Modbus_RTU modbus_RTU;
MD_RTU_MsgPut((PModbusBase)(&modbus_RTU), MD_RTU_MSG_HANDLE_ARG(&modbus_RTU),(void*)(data),0);
#endif
}
}
#include "MDS_RTU_APP_1.h"
#include "MD_RTU_MapTable.h"
#include "MDS_RTU_Fun.h"
#include "MDS_RTU_User_Fun.h"
#include "MDS_RTU_Serial_1.h"
#include "b5wc.h"
#define SALVE_ADDR 0x02
static void MDSAPPWriteFunciton(void* obj,uint16 modbusAddr,uint16 wLen,AddrType addrType);
void MDSAPPWriteFunciton(void* obj,uint16 modbusAddr,uint16 wLen,AddrType addrType);
#ifdef MDS_USE_IDENTICAL_MAPPING
STATIC_T uint16 mapTableData0[32]={1,2,3,4,5,6,7,8,9,10,11,12};
STATIC_T MapTableItem mapTableItem0={
.modbusAddr=0x0000,
.modbusData=mapTableData0,
.modbusDataSize=32,
.addrType=HOLD_REGS_TYPE
};
STATIC_T uint16 mapTableData2[32]={11,21,31,41,51,61,71,81,91,101,111,121};
STATIC_T MapTableItem mapTableItem2={
.modbusAddr=0x0000,
.modbusData=mapTableData2,
.modbusDataSize=32,
.addrType=INPUT_REGS_TYPE
};
STATIC_T uint16 mapTableData1[4]={0};
STATIC_T MapTableItem mapTableItem1={
.modbusAddr=0x0000,
.modbusData=mapTableData1,
.modbusDataSize=64,
.addrType=COILS_TYPE
};
STATIC_T uint16 mapTableData3[4]={0x5555,0x5555};
STATIC_T MapTableItem mapTableItem3={
.modbusAddr=0x0000,
.modbusData=mapTableData3,
.modbusDataSize=64,
.addrType=INPUT_TYPE
};
#else
extern MapTableItem mapTableItem0;
extern MapTableItem mapTableItem1;
extern MapTableItem mapTableItem2;
extern MapTableItem mapTableItem3;
#endif
static uint8 MDSRecvQueueData[MDS_RTU_QUEUE_SIZE+1]={0};
static uint8 MDSMsgProcessQueueData[MDS_RTU_QUEUE_SIZE+1]={0};
static ModbusS_RTU modbusS_RTU={0};
BOOL MDS_RTU_APPInit_1(void){
MDS_RTU_Init(&modbusS_RTU,MDSInitSerial_1,SALVE_ADDR,9600,8,1,0);
MDS_RTU_QueueInit(&modbusS_RTU,
MDSRecvQueueData,
sizeof(MDSRecvQueueData),
MDSMsgProcessQueueData,
sizeof(MDSMsgProcessQueueData)
);
if(MDS_RTU_AddMapItem(&modbusS_RTU,&mapTableItem0)==FALSE){
return FALSE;
}
if(MDS_RTU_AddMapItem(&modbusS_RTU,&mapTableItem1)==FALSE){
return FALSE;
}
if(MDS_RTU_AddMapItem(&modbusS_RTU,&mapTableItem2)==FALSE){
return FALSE;
}
if(MDS_RTU_AddMapItem(&modbusS_RTU,&mapTableItem3)==FALSE){
return FALSE;
}
MDS_RTU_SetWriteListenFun(&modbusS_RTU,MDSAPPWriteFunciton);
return TRUE;
}
static void MDS_RTU_UserUpdate(void){
u16 rgb_value[3]={0};
u16 zb_value[3]={0};
b5cw_RGB_value_get(rgb_value);
zb_value[0]=rgb_value[0]*100/(rgb_value[0]+rgb_value[1]+rgb_value[2]);
zb_value[1]=rgb_value[1]*100/(rgb_value[0]+rgb_value[1]+rgb_value[2]);
zb_value[2]=rgb_value[2]*100/(rgb_value[0]+rgb_value[1]+rgb_value[2]);
MDS_RTU_WriteHoldRegs(&modbusS_RTU,5,3,rgb_value);
MDS_RTU_WriteHoldRegs(&modbusS_RTU,8,3,zb_value);
}
static void MDSAPPWriteFunciton(void* obj,uint16 modbusAddr,uint16 wLen,AddrType addrType){
uint16 data[8]={0};
uint8 temp=MD_H_BYTE(data[0]);
if((&modbusS_RTU)!=obj){return ;}
switch(addrType){
case COILS_TYPE:
MDS_RTU_ReadCoils(obj,modbusAddr,wLen, (uint8*)data);
data[0]=data[0];
break;
case INPUT_TYPE:
break;
case HOLD_REGS_TYPE:
MDS_RTU_ReadHoldRegs(obj,modbusAddr,wLen<8?wLen:8, data);
temp=MD_L_BYTE(data[0]);
temp=temp;
break;
case INPUT_REGS_TYPE:
break;
}
}
void MDS_RTU_Loop_1(void){
MDS_RTU_Process(&modbusS_RTU);
MDS_RTU_UserUpdate();
}
#include "debug.h"
#include "b5wc.h"
#include "tim3.h"
#include "Sys_Config.h"
#if MD_USD_SALVE
#include "MDS_RTU_APP_1.h"
#else
#include "MDM_RTU_APP.h"
#include "MDM_RTU_Fun.h"
#include "MDM_RTU_User_Fun.h"
#endif
u16 mem_size[2]={0};
u32 uid[3]={0};
u16 rgb_value[3]={0};
#if MD_RTU_USED_OS
PTASK_TCB task0;
PTASK_TCB task1;
PTASK_TCB task2;
extern Modbus_RTU_CB modbusRWRTUCB;
extern Modbus_RTU_CB modbusRWRTUCB1;
void mdTestTask0(void *arg){
uint16 temp;
for(;;){
if(ERR_RW_FIN==MDM_RTU_ReadHoldReg(&modbusRWRTUCB,1,0,1)){
MDM_RTU_ReadRegs(modbusRWRTUCB.pModbus_RTU,0,1, (&temp),HOLD_REGS_TYPE,0x1);
}
OSTaskDelay(500);
}
}
void mdTestTask1(void *arg){
uint16 temp=0;
for(;;){
if(ERR_RW_FIN==MDM_RTU_WriteSingleReg(&modbusRWRTUCB1,2,0,temp)){
}
temp++;
OSTaskDelay(500);
}
}
#endif
int main(void)
{
#if MD_RTU_USED_OS
OSInit();
#endif
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Delay_Init();
USART_Printf_Init(9600);
b5cw_init();
#if MD_USD_SALVE
MDS_RTU_APPInit_1();
#else
MDM_RTU_APPInit();
#endif
TIM3_Int_Init(96-1,100-1);
#if MD_RTU_USED_OS
task1=OSCreateTask(mdTestTask0,NULL,6,256);
task2=OSCreateTask(mdTestTask1,NULL,6,256);
SysTick_Config(SystemCoreClock / OS_TICKS_PER_SEC);
OSStart();
#endif
while(1){
#if !MD_RTU_USED_OS
#if MD_USD_SALVE
MDS_RTU_Loop_1();
#else
MDM_RTU_Loop();
MDM_RW_CtrlLoop();
#endif
#endif
}
}
主函数就处理Modbus响应,传感器采用IIC协议,开发采用硬件IIC,MOdbus应用读取RGB分量值,并计算比例。
现场安装如图所示:
现场采集结果展示
)