GPIO port analog serial port sending and receiving (based on H861)

I used to hear that code farmers need to have strict logical thinking, but I didn't understand it before. Without a framework of thinking, it is really difficult to write code. I can’t be blinded. What’s waiting for me is inefficiency.

Ideas

First of all, if we want to simulate serial communication, we must understand the necessary conditions of communication, including data bits and other flag bits, as well as his timing, which is a bit like analog IIC.
Insert picture description here
The figure shows the format of the data. The data bits are eight bits, not seven bits. Of course, there are data bits as seven bits. In the actual transmission process, I choose the start bit + data as + stop bit , and the parity check Check bit and free bit are not necessary . Just know the data to be transmitted, but the other party does not know when to receive the data, so we now need a protocol (uart serial port protocol) to put the data on this protocol, so that we can make If the upper computer or lower computer of the communication can recognize the transmitted data, what else is needed? ?
We all know that we have settings when we use serial port software (just for example, there are too many serial port software) as shown in the figure:
Insert picture description here
baud rate, data bit, parity bit, stop bit can all be changed.
Concept of baud rate: baud rate represents the number of symbol symbols transmitted per second. It is a measure of symbol transmission rate. It is expressed by the number of times the carrier modulation state changes per unit time. 1 baud means Refers to the transmission of 1 symbol per second.
Generally, we use the form of analog to communicate generally at 9600 and below. If it is higher, the accuracy cannot be guaranteed.

Here, the analog baud rate is 9600 for communication (normally, the lower the baud rate, the less difficult it is)

9600 means that 9600 bits are sent every second (including non-data bits). Note that this is not a byte ( it cannot be regarded as 9600/8=1200byte ). Many friends who have not done this experiment are not clear about this Conceptual. Ideally, according to this transmission baud rate, the time interval for sending each bit is 104us.
To communicate, there are sending and receiving. Sending is relatively simpler than receiving.

Serial port send

The most important thing in sending is the control of time, because it is subtle and needs to be very precise. I use timers for timing.

Timer initialization : here we can directly use the API (hi_u32 is a 32-bit data definition), if you need to adapt your own IC, just create it according to the timer creation

void io_hrtimer_init(hi_u32 *g_hrtimer)
{
    
    
    hi_u32 ret;
    /* create timer handle */
    ret = hi_hrtimer_create(g_hrtimer);//创建定时器
    if (ret != HI_ERR_SUCCESS)
    {
    
    
        printf("=====ERROR===== hrtimer handle create ret is: %d !!\r\n", ret);
        return;
    }
    printf("----- hrtimer handle create success -----\n");
}

GPIO initialization : each API has a comment

void io_uart_tx_init(void)
{
    
    
    hi_u32 ret;
    ret = hi_gpio_init(); //GPIO初始化
    if (ret != HI_ERR_SUCCESS)
    {
    
    
        printf("===== ERROR ===== gpio -> hi_gpio_init ret:%d\r\n", ret);
        return;
    }
    printf("----- gpio init success-----\r\n");

    ret = hi_io_set_func(HI_IO_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_GPIO);//开启GPIO复用
    if (ret != HI_ERR_SUCCESS)
    {
    
    
        printf("===== ERROR ===== gpio -> hi_io_set_func ret:%d\r\n", ret);
        return;
    }
    printf("----- io set func success-----\r\n");

    ret = hi_gpio_set_dir(HI_GPIO_IDX_14, HI_GPIO_DIR_OUT);//设置管脚方向
    if (ret != HI_ERR_SUCCESS)
    {
    
    
        printf("===== ERROR ===== gpio -> hi_gpio_set_dir1 ret:%d\r\n", ret);
        return;
    }
    printf("----- gpio set dir success! -----\r\n");
    hi_gpio_set_ouput_val(HI_GPIO_IDX_14, HI_GPIO_VALUE1); //初始化输出高电平
}

Timer delay function and callback interrupt :

static hi_void hrtimer_callback(hi_u32 data)
{
    
    
    block_or_go_on = 0;
}
void hr_delay(hi_u32 time)
    int ret;
    ret = hi_hrtimer_start(rx_timer, time, hrtimer_callback, go_on);
    if (ret != 0)
    {
    
    
        printf("-----hi timer faild-----\r\n");
    }
    printf("block_or_go_on:%d\r\n", block_or_go_on);
    while (block_or_go_on);
    block_or_go_on = 1;
}

Stop function

void stop_function(void)
{
    
    
    hi_hrtimer_start(g_hrtim, (time_), hrtimer_callback, go_on);//开启定时器API
    io_uart_tx(1);
    while (!block_or_go_on);
    block_or_go_on = 1;
}

Start function

void start_function(void)
{
    
    
    hi_hrtimer_start(g_hrtim, (time_), hrtimer_callback, go_on);//开启定时器API	
    io_uart_tx(0);
    while (!block_or_go_on);
    block_or_go_on = 1;
}

Main function :

#define time_ (100)
#define block 0
#define go_on 1
 main()
{
    
    
#define time_ (100)
static volatile char block_or_go_on = 1;
int ret = 0;
    int i = 0;
    char data;
    hi_u32 g_hrtim;
    char b[] = {
    
    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
    io_uart_tx_init();
    io_hrtimer_init(&g_hrtim);
    for (;;)
    {
    
    
printf("---has enter TX----\r\n");
        for (ret = 0; ret < 100; ret++)//发送100个数据,查看是否有误
        {
    
    
            data = b[ret];
            start_function();
            for (i = 0; i < 8; i++)
            {
    
    
                hi_gpio_set_ouput_val(HI_GPIO_IDX_14, data & 0x01);//发送数据API
                hr_delay(time_ - 5);
                data >>= 1;
            }
            stop_function();
        }
        hr_delay(2000000);
    }
    }

What I want to explain here is that I combine the start bit with a certain delay, and the same is true for the stop bit. The delay is added after the data bit to form the entire sequence. After writing, the data is generally wrong. We can use the serial port software to receive and see the received data. Because the program takes time to run, it is generally not 104us. I call it 100us, but I have to change it according to my own situation. The code framework is ok.

Serial port reception (still 9600)

Idea: Turn on the timer interrupt, turn off the interrupt after entering the interrupt, perform high and low level judgments in the interrupt function, and finally convert these bits into the required data, that is to say, an interrupt function completes the reception of one byte!
Timer initialization and interrupt

static hi_void hrtimer_callback(hi_u32 data)
{
    
    
    block_or_go_on = 0;
}
void io_hrtimer_init(hi_u32 *g_hrtimer)
{
    
    
    hi_u32 ret;
    /* create timer handle */
    ret = hi_hrtimer_create(g_hrtimer);
    if (ret != HI_ERR_SUCCESS)
    {
    
    
        printf("=====ERROR===== hrtimer handle create ret is: %d !!\r\n", ret);
        return;
    }
    printf("----- hrtimer handle create success -----\n");
}

GPIO interrupt initialization and interrupt function : see notes

static volatile hi_u32 irq_flag=0;
static void irq_function(hi_void *arg)
{
    
    
    hi_gpio_deinit();
    irq_flag = 1;
    printf("-----has enter irq_function-----\r\n");
}
void gpio_rx_irq_init(void)
{
    
    
    hi_u32 ret;
    ret = hi_gpio_init(); //注意,该接口不支持重复调用,只能在初始化阶段调用一次
    //irq_flag = ret;
    if (ret != HI_ERR_SUCCESS)
    {
    
    
        printf("===== ERROR ===== gpio -> hi_gpio_init ret:%d\r\n", ret);
        return;
    }
    printf("----- gpio init success-----\r\n");

    ret = hi_gpio_set_dir(HI_GPIO_IDX_5, HI_GPIO_DIR_IN);//方向
    if (ret != HI_ERR_SUCCESS)
    {
    
    
        printf("===== ERROR ===== gpio -> hi_gpio_set_dir ret:%d\r\n", ret);
        return;
    }
    printf("----- dir init success-----\r\n");

    ret = hi_io_set_func(HI_GPIO_IDX_5, HI_IO_FUNC_GPIO_5_GPIO);//复用
    if (ret != HI_ERR_SUCCESS)
    {
    
    
        printf("===== ERROR ===== gpio -> hi_io_set_func ret:%d\r\n", ret);
        return;
    }
    printf("----- io set func success-----\r\n");
    ret = hi_gpio_register_isr_function(HI_GPIO_IDX_5, HI_INT_TYPE_EDGE, HI_GPIO_EDGE_FALL_LEVEL_LOW, irq_function, 0); //开启中断功能
    if (ret != HI_ERR_SUCCESS)
    {
    
    
        printf("===== ERROR ===== gpio -> hi_gpio_register_isr_function ret:%d\r\n", ret);
        return;
    }
    printf("----- func init success-----\r\n");
}

Main function

#define _time_ (100)
#define BIT(x) (0x01<<(x))
#define block 0
#define go_on 1
main()
{
    
    
    hi_u32 rx_timer;
    io_hrtimer_init(&rx_timer); //定时器初始化
    gpio_rx_irq_init();
    for (;;)
    {
    
    
        if (irq_flag == 1)
        {
    
    
            int ret = 0;
            int electric_level[3] = {
    
    0};
            int bit_value;
            char data = 0;
            for (ret = 0; ret < 10; ret++)//数据位+停止位+开始位=10
            {
    
    
                hi_hrtimer_start(rx_timer, (_time_ - 8), hrtimer_callback, go_on);//进行了时间数据的微调
                while (block_or_go_on);
                block_or_go_on = 1;
                hi_gpio_get_input_val(HI_GPIO_IDX_5, &bit_value);
                if (ret == 8) //第九位停止位为1
                {
    
    
                    printf("4\r\n");

                    break;
                }
                if (bit_value == 1)
                {
    
    
                    data |= BIT(ret);
                    printf("1\r\n");
                }
                else
                {
    
    
                    printf("0\r\n");
                }
                block_or_go_on = 1;//置1
            }
            printf("%02X ", data);
            irq_flag = 0;//中断标志位置1
            hi_gpio_init();//开启中断
        }
    }
}

Here I just give a code framework. The details need to be adjusted by myself. If you can’t do all copy, it’s ok. Why don’t you do it in the interrupt this time? Because the priority of the IC's GPIO and timer interrupts I use is The same and cannot be modified.
I tried the above correct receiving time, it will only be around 104, it also depends on the degree of simplification of your code!

Guess you like

Origin blog.csdn.net/weixin_42271802/article/details/108446639