Introduction

Generally, the signal current of the general instrument is 4-20mA, which means that the minimum current is 4mA and the maximum current is 20mA. When transmitting a signal, consider that there is resistance on the wire, if the voltage transmission will produce a certain voltage drop in the wire, the signal at the receiving end will produce a certain error, so the current signal is used as the standard transmission of the transmitter. Why choosing 4-20mA instead of 0-20mA? 4ma is used to detect the line open, if 0 is the smallest, then the open circuit fault can not be detected. To solve these problems and avoid the effects of related noise, we use currents to transmit signals because currents are not sensitive to noise. The current ring of 4 to 20mA is a zero signal with 4mA, a full scale of the signal with 20mA, and a signal below 4mA and above 20mA is used for various fault alarms.

Many controllers accept 0 to 20mA or 4 to 20mA currents from various instruments and make a 0-20mA signal generator that can help to calibrate and test many different instruments.

2. Overal Design

2.1. Target

2.2. Design

Taking STM32F030C8T6 for this experiment as it has 4 PWM output and great supports on opensource RT-Thread Real-Time Operating System. And I take a 0-96 inch OLED.

2.2.1.Hardware circuits

Figure 1 is a typical circuit of voltage-to-current. The single-chip outputs PWM, the control Vi voltage level is between 0-3V, and the current flowing through the RL is 0-20mA.

Figure 2 OLED display circuit

Because the MCU can be configured with pull-up resistors, the keys can be directly connected to the MCU.

Figure 3 Key circuit

2.2.2.Software Design

2.2.3. Key Point Code

Key Code.

/* key thread entry */
static void key_thread_entry(void* parameter)
{
    KEY_e i;
    uint8_t key_state1[KEY_NUM];
    uint8_t key_state2[KEY_NUM];
    uint8_t key_counter[KEY_NUM];
    rt_base_t level;

    memset(key_counter, 0, sizeof(key_counter));
    while(1)
    {
        for (i=KEY1; i<KEY_NUM; i++)
        {
            key_state1[i] = rt_hw_key(i);
        }
        rt_thread_delay(RT_TICK_PER_SECOND / 20);
        for (i=KEY1; i<KEY_NUM; i++)
        {
            key_state2[i] = rt_hw_key(i);
        }
        for (i=KEY1; i<KEY_NUM; i++)
        {
            if (key_state1[i] == key_state2[i] &&
                key_state1[i] == 0)
            {
                level = rt_hw_interrupt_disable();
                if (key_counter[i] == 0)
                {
                    switch(i)
                    {
                        case KEY2:
                            if (pwm_channel < 3)
                            {
                                pwm_channel++;
                            }
                            break;
                        case KEY1:
                            if (pwm_channel > 0)
                                pwm_channel--;
                            break;
                        case KEY3:
                            if (pwm_value[pwm_channel] < 20000)
                                pwm_value[pwm_channel]++;
                            break;
                        case KEY4:
                            if (pwm_value[pwm_channel] > 0)
                                pwm_value[pwm_channel]--;
                            break;
                        case KEY5:
                            if (pwm_value[pwm_channel] < 16000)
                                pwm_value[pwm_channel] += 4000;
                            else
                                pwm_value[pwm_channel] = 20000;
                            break;
                        case KEY6:
                            if (pwm_value[pwm_channel] >= 4000)
                                pwm_value[pwm_channel] -= 4000;
                            else
                                pwm_value[pwm_channel] = 0;
                            break;
                    }
                    rt_kprintf("key %d clicked\r\n",  i);
                }
                if (key_counter[i] >= 5)
                {
                    switch(i)
                    {
                        case KEY2:
                            if (pwm_channel < 3)
                            {
                                pwm_channel++;
                            }
                            break;
                        case KEY1:
                            if (pwm_channel > 0)
                                pwm_channel--;
                            break;
                        case KEY3:
                            if (pwm_value[pwm_channel] < 20000)
                                pwm_value[pwm_channel]++;
                            break;
                        case KEY4:
                            if (pwm_value[pwm_channel] > 0)
                                pwm_value[pwm_channel]--;
                            break;
                        case KEY5:
                            if (pwm_value[pwm_channel] < 16000)
                                pwm_value[pwm_channel] += 4000;
                            else
                                pwm_value[pwm_channel] = 20000;
                            break;
                        case KEY6:
                            if (pwm_value[pwm_channel] >= 4000)
                                pwm_value[pwm_channel] -= 4000;
                            else
                                pwm_value[pwm_channel] = 0;
                            break;
                    }
                    rt_kprintf("key %d pressed\r\n",  i);
                }
                if (key_counter[i] < 5)
                {
                    key_counter[i]++;
                }
                rt_hw_interrupt_enable(level);
            }
            else
            {
                key_counter[i] = 0;
            }
        }
        rt_thread_delay(RT_TICK_PER_SECOND / 100);
    }
}

oled display code. 

/* oled thread entry */
static void oled_thread_entry(void* parameter)
{
    uint8_t i;
    rt_base_t level;
    char str_pwm[64];
    
    OLED_Init();
    OLED_Clear();
    PWM_TIM1(999, 1); //48MHZ/(999+1)/(1+1) = 24KHZ
    while(1)
    {
        //OLED_ShowString(0,...
Read more »