Hardware

1. Motivation

This project aims to study drug-resistant microorganisms in the ocean, and we have designed a portable marine drug-resistant microorganism detector for this field. Currently, there are testing tools such as enzyme markers, but these devices are costly and large, and most of the human-machine interfaces use a computer screen to connect to them and then perform the relevant operations, which is very inconvenient. Therefore, considering several aspects such as cost, portability and easy operation process, we developed a hardware system specifically adapted to our needs. The system is relatively small, can achieve rapid detection, and the human-machine interface is friendly and easy to operate.

Full view of the instrument:

png

2. Hardware Components

The system has 3 main modules, mainly divided into temperature regulation module, light path detection module and Android screen display module. The following shows the system block diagram.

png

2.1 Temperature regulation

The samples need to be tested at a constant temperature, so here we made a heating film with a rated power of 20w and attached it to the surface of the heat-conducting aluminum according to its dimensions. Using a temperature sensor, the temperature sensor is inserted directly into the thermal conductive aluminum, so it is more accurate and real-time monitoring of the internal culture temperature of the thermal conductive aluminum. Using stm32f103c8t6 master control chip, with pid algorithm to control the temperature rise and final stabilization.

Special thermally conductive aluminum, heating film and temperature sensor physically connected to.

png

Assuming that the set temperature is 37℃, after the actual test, it can be obtained that it takes 260s to rise from room temperature 28℃ to the set temperature. the overshoot after reaching the set temperature is within 0.2℃, and the final temperature can be stabilized at about 37℃ with an error of ±0.1℃. Compared with some traditional enzyme markers, the time to warm up and reach the stable temperature is faster.

png

pid algorithm to regulate the temperature

png

Temperature change curve with time

2.2 Optical path structure

At the light source end, we use led light beads, which are small in size, consume less power at the same brightness, have high luminous efficiency, fast response time, and do not exist such as mercury, lead and other environmental pollutants, known as "green light source". Optical fiber is used to transmit the light path to the bottom of the culture chamber. We use special structural components to isolate each light source, avoiding interference from the bypass.

At the receiving end we use a photodiode, which transmits the generated fluorescence to the photodiode in the horizontal direction of the incubation chamber using an optical fiber. The photodiode receives the fluorescence and generates a photocurrent at the uA level, which is then detected through IV conversion, amplification circuits and A/D conversion.

png png

Receiver side circuit design:

png png
png png

Physical picture:

png

2.3 Android screen display

In order to improve good user experience, we have developed a software interface based on the off-the-shelf Android screen for users to use. The workflow of the whole instrument is clear on the Android screen.

png

2.4 Equipment Demonstration

2.4.1 Set sample description, including sample name, incubation chamber temperature, test duration, etc.

png

2.4.2 Click the Start Detection button.

png

2.4.3 Temperature is reached prompting the sample to be placed in the incubation chamber.

png

2.4.4 Wait for the end of the test or click the End Test button to end the process.

png

To demonstrate the feasibility of a portable marine drug-resistant microbial assay, we used standard enzyme markers for the same samples in order to compare the results.

After the comparison of the results, the results of the portable marine drug-resistant microbial detector were basically consistent with those of the enzyme marker, which proved the feasibility of the portable marine drug-resistant microbial detector.

2.5 Circuit Design

The circuit design of the portable marine drug resistance microbial detector was implemented using a PCB board, mainly with a main board and a receiver board. The off-the-shelf components are a 7" Android screen, temperature sensor, 20w heating film, Android screen for developing the software interface, after powering up, all the operations of the instrument can be realized using the buttons on the Android screen interface, and the user without any experience can fully master the operation of the instrument.

The main board mainly consists of voltage conversion module, stm32f103c8t6 module, receiver board interface, Android screen interface, serial port 1 interface, STLINK interface, temperature sensor interface, heating film drive circuit.

Main board PCB:

>
png

The receiver board mainly consists of a light source module, a photodiode module, a motherboard interface and an AD conversion module. Receiver board PCB front:

png

Receiver board PCB back:

png

The whole system can be realized by 12v adapter power supply.

System circuit design:

png png
png png

Future improvements

At present, the entire structure of the portable marine drug-resistant microbial detector is printed out by a 3D printer, so the printed structure will deviate slightly from the actual design of the 3D model, and the aesthetic appearance is relatively poor. The temperature sensor protrudes above the thermally conductive aluminum material, resulting in some unreasonable internal structure, but it does not affect the test.

In order to solve the above problems, we have proposed several solutions.

For the instrument appearance problem: the structure will be transferred to a professional foundry.

For the temperature sensor problem:

1. design the temperature sensor interface below or to the side of the thermal conductivity aluminum;

2. replace the inline temperature sensor with an infrared temperature sensor.

The related codes is following

Temperature regulation by Pid algorithm:

void PID_Calc(void){ if (pid.Sv > 50) { pid.Sv = 50; } pid.Ek = pid.Sv - pid.Pv; if (pid.Ek > 1) { pid.OUT = pid.pwmcycle; pid.SEk = 0; pid.Ek_1 = 0; } else if (pid.Ek < -0.3) { pid.OUT = -pid.pwmcycle; pid.SEk = 0; pid.Ek_1 = 0; } else { pid.SEk += pid.Ek; DelEk = pid.Ek - pid.Ek_1; pid.Ek_1 = pid.Ek; pid.Pout = pid.Kp * pid.Ek; pid.Iout = pid.Ki * pid.SEk; pid.Dout = pid.Kd * DelEk; pid.out = pid.Pout + pid.Iout + pid.Dout; if (pid.out > pid.pwmcycle) { pid.OUT = pid.pwmcycle; } else if (pid.out < -pid.pwmcycle) { pid.OUT = -pid.pwmcycle; } else { pid.OUT = pid.out; } } }

The control code for the MCU is:

void sys_initial(void){ delay_init(); LED_GPIO_Config(); DS18B20_Init(); PID_Init(500, 3, 16000, DEFAULT_TEMP); Isr_Init(); USART1_Config(); USART2_Config(); PIDOUT_Init(); TIM3_Init(); TIM2_Init(); TIM4_Init(); TWI_Initialize(); //IWDG_Init(6,125); } void TIM3_IRQHandler() //500ms { static int sesc, sesc1; u8 st; st = TIM_GetFlagStatus(TIM3, TIM_IT_Update); if (st != 0) { sesc++; sesc1++; TIM_ClearITPendingBit(TIM3, TIM_IT_Update); read = read + 1; ReadTemp_flag = 1; DS18B20_Get_Temp(); while (ReadTemp_flag == 0) { ReadTemp_flag = 1; DS18B20_Get_Temp(); } ReadTemp_flag = 0; PID_Calc(); PID_out(); if (sesc > 6) { send_temp(); sesc = 0; } if (sesc1 > 9) { printf("%f\r\n", pid.Pv); sesc1 = 0; } } } void TIM4_IRQHandler(){ u16 len = 0; u8 j; if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) { if (testMode == 1) { pwmValueCheck(); FLASH_Unlock(); STMFLASH_Erase(PWM_SAVE_ADDR); STMFLASH_Write(PWM_SAVE_ADDR, (u16 *) & pwm_value, sizeof(pwm_value) / 2); FLASH_Lock(); testMode = 2; } TIM_ClearITPendingBit(TIM4, TIM_IT_Update); } return; } void TIM2_IRQHandler(){ static int sesc1, sesc2; int i; if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { sesc1++; if (sesc1 > 500 && (first == 1 || done == 1)) { send_temp(); done = 0; sesc1 = 0; sendAdc(); } if (sesc2 > 10) { if (testMode) { pwmValueCheck(); for (i = 0; i < 16; i++) { Usart_SendODData(USART2, 0xF1, (0xB1 << 8 | i), adcTemp[i]); } FLASH_Unlock(); STMFLASH_Erase(PWM_SAVE_ADDR); STMFLASH_Write(PWM_SAVE_ADDR, (u16 *) & pwm_value, sizeof(pwm_value) / 2); FLASH_Lock(); Usart_SendODData(USART2, 0xF1, 0xB300, 0x0000); testMode = 0; } } } TIM_ClearITPendingBit(TIM2, TIM_IT_Update); } void sendAdc(void){ int i; if (Ready_status == 1) { first = 0; getAdcValue(); for (i = 0; i < 16; i++) { Usart_SendODData(USART2, i, 0x0001, adcValue[i]); } } } void send_temp(void){ u16 temp_h; temp_h = pid.Pv * 100; Usart_SendODData(USART2, 0xF1, 0x7000, temp_h); if (fabs(pid.Pv - pid.Sv) <= 0.2 && temp_set == 1) { Usart_SendODData(USART2, 0xF1, 0x9000, 0); temp_set = 0; } } void USART2_IRQHandler(void){ if (ReadTemp_flag == 1) { ReadTemp_flag = 0; } if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) { save[i] = USART_ReceiveData(USART2); if (save[0] == 0x36) { if (i <= len) { check ^= save[i]; } i++; } if (i >= len + 3) { if ((check == save[len + 1]) && (save[0] == 0x36) && (save[len + 2] == 0xFF) && (save[1] == 0xF1)) { key = save[2]; switch (key) { case 0x03: { Usart_SendODData(USART2, 0xF1, 0x3000, 0x0000); } break; case 0x04: { pid.Sv = 0; S_status = 0; Ready_status = 0; testMode = 0; first = 1; Usart_SendODData(USART2, 0xF1, 0x4000, 0x0000); } break; case 0x05: { Usart_SendODData(USART2, 0xF1, 0x5000, 0x0000); delay_ms(10); SoftReset(); } break; case 0x08: { pid.Sv = save[3]; temp_set = 1; Usart_SendODData(USART2, 0xF1, 0x8000, 0x0000); } break; case 0x09: { Ready_status = 1; } break; case 0x0a: { } break; case 0x0c: { testMode = 1; Usart_SendODData(USART2, 0xF1, 0xc000, 0x0000); } break; case 0x0b: { } break; } } i = 0; for (n = 0; n <= len + 2; n++) { save[n] = 0; } check = 0; } } } void SoftReset(void) { __set_FAULTMASK(1); NVIC_SystemReset(); } void Usart_SendODData(USART_TypeDef * pUSARTx, uint8_t ch, uint16_t ch1, uint16_t ch2) { uint8_t temp1_h, temp1_l, temp2_h, temp2_l; uint8_t a[12] = { 0}, check = 0x36, i = 0; a[0] = ch; temp1_h = (ch1 & 0XFF00) >> 8; a[1] = temp1_h; temp1_l = ch1 & 0XFF; a[2] = temp1_l; temp2_h = (ch2 & 0XFF00) >> 8; a[3] = temp2_h; temp2_l = ch2 & 0XFF; a[4] = temp2_l; Usart_Send_Byte(pUSARTx, 0x36); for (i = 0; i < 5; i++) { Usart_Send_Byte(pUSARTx, a[i]); check ^= a[i]; } Usart_Send_Byte(pUSARTx, check); Usart_Send_Byte(pUSARTx, 0xFF); } void USART2_Config(void){ GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, & GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, & GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 115200; 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(USART2, & USART_InitStructure); NVIC_Configuration(); USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); USART_Cmd(USART2, ENABLE); } static void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(& NVIC_InitStructure); }