基于alios系统门禁uart串口应用编写

引言

作为郑州的嵌入式新人,最近接到两个任务,第一个是根据门禁设备的驱动程序写出一个接受串口数据的应用,这个串口用于连接读卡器等设备。第二个是把libpng移植到门禁设备上,由于我们的门禁设备只支持jpg格式的图片,因此要用这个库把png图片转为raw格式,然后再转换为jpg格式。第一个任务以及完成,今天先整理第一个任务。

开发过程及源码

首先在主程序中重新开一个串口任务

#if defined(USING_UART_Receive_ENABLE) 	
     #define UART_RECEIVE_PRI 31
	 printf("uart_receive test.\n");
	 aos_task_t uart_receive_thread;
	 ret = aos_task_new_ext(&uart_receive_thread, "uart_receive", uart_reader_task, NULL, 10*1024, UART_RECEIVE_PRI);
#endif 

在uart_reader_task函数中进行串口的初始化,配置等操作,首先进行引脚复用,然后使能时钟,开启相应引脚功能,由于是多线程任务,为了保证数据的完成行,创建信号量进行处理。在本任务中主要需要关注的是csi_uart_initialize(),csi_uart_config(),csi_uart_receive()。

void uart_reader_task(void *paras)
{	
	uint8_t *p;
	int i=0;
	int ret=-1;
	int rece_size =0;
	int cnt;
    device_event_t * evt;

	drv_pinmux_config(OTP_MUX,UART1_MUX);

    drv_disable_uart_clock(1);
    drv_uart_clk_sel(1, CLK_SEL_PLL);
	drv_enable_uart_clock(1);
    drv_set_uart_freq(1,10,275);

    ret = krhino_sem_create(&uart_reader_sem, "UART-READER-SEM", 0);
    if (ret != RHINO_SUCCESS) {
        return ret;
    }
    handle = csi_uart_initialize(1, uart_receive_event_cb);
   

    ret = csi_uart_config(handle, 9600,UART_PARITY_NONE,UART_STOP_BITS_1, UART_DATA_BITS_8);

    csi_uart_receive(handle,NULL,0);

   while(1)
   {
        ret = krhino_sem_take(&uart_reader_sem, RHINO_WAIT_FOREVER);
        if (ret != RHINO_SUCCESS) {
            k_err_proc(ret);
        }
        if(uart_reader_state == UART_READER_STATE_FULL)
        {
            evt = device_event_construct("open",DeviceEventTypeOperation);

            if(evt)
            {
                evt->data =device_event_alloc(evt,16);
                p = evt->data;
                *p = 0x26;
                p++;

                *p = uart_reader_frame[9];
                p++;
                *p = uart_reader_frame[8];
                p++;
                *p = uart_reader_frame[7];
                
                device_event_notify(evt);
            }
            uart_reader_state = UART_READER_STATE_INIT;
        }
   }
//	ret = csi_uart_uninitialize(handle);
}

其中有意思的是在初始化配置的时候还能这样定义结构体数组,让我惊呆了(菜鸟新人看的代码少,没见过世面)这样的写法让代码看着更加整洁美观。到这一步串口已经配置好,相应的中断已经打开,众所周知,串口的接收主要靠中断完成,由于刚入行先从嵌入式应用做起,驱动我就不那么细看了,主要关心厂家给出的接口。

struct {
    uint32_t base;
    uint32_t irq;
    void *handler;
}
static const sg_uart_config[CONFIG_UART_NUM] = {
    {CSKY_UART0_BASE,  UART0_IRQn,  UART0_IRQHandler},
    {CSKY_UART1_BASE,  UART1_IRQn,  UART1_IRQHandler},
    {CSKY_UART2_BASE,  UART_CK804_IRQn,  UART_CK804_IRQHandler},
    {CSKY_UART3_BASE,  UART_CK805_IRQn,  UART_CK805_IRQHandler},
};

int32_t target_uart_init(int32_t idx, uint32_t *base, uint32_t *irq, void **handler)
{
    if (idx >= CONFIG_UART_NUM) {
        return -1;
    }

    if (base != NULL) {
        *base = sg_uart_config[idx].base;
    }

    if (irq != NULL) {
        *irq = sg_uart_config[idx].irq;
    }

    if (handler != NULL) {
        *handler = sg_uart_config[idx].handler;
    }

    return idx;
}

在中断函数中进入相应的事件,由于是接收,进入 ck_uart_intr_recv_data(uart_priv);这个函数

void ck_uart_irqhandler(int idx)
{
    ck_uart_priv_t *uart_priv = &uart_instance[idx];
    ck_uart_reg_t *addr = (ck_uart_reg_t *)(uart_priv->base);

    uint32_t intr_state = addr->UART_FCR_IIR & 0xf;

	if (intr_state & IIR_INT_TX_EMPTY) {
        ck_uart_intr_send_empty(uart_priv);
	} else if (intr_state & IIR_INT_RX_THOLD) {
        ck_uart_intr_recv_data(uart_priv);
	} else if (intr_state & IIR_INT_UART_STOP) {
        ck_uart_intr_char_timeout(uart_priv);     //receive small data
	} else if (intr_state & IIR_INT_UART_PERR) {
        ck_uart_intr_process_error(uart_priv);
	}
}

在初始化串口的时候已经把回调函数注册进去了,在串口进入相应事件的时候会调用回调函数,我们根据状态在回调函数中对串口进行处理。在本项目中主要应用了UART_EVENT_RECEIVED这个事件,csi_uart_receive_query这个函数是从FIFO(First Input First Output的缩写,先入先出队列中)读取数据

static void uart_receive_event_cb(int32_t idx, uint32_t event)
{
    int rx_count;   
    switch (event) {
        case UART_EVENT_SEND_COMPLETE:
       //     printf("send complete!!!!!!\r\n");
             break;
        case UART_EVENT_RX_TIMEOUT:
            uart_reader_state = UART_READER_STATE_INIT;
            break;
        case UART_EVENT_RECEIVE_COMPLETE:
        
            rx_count = drv_usi_usart_get_rx_count(handle);
         //   printf("rx_count  %d\n",rx_count);
            
            break;
    
		case UART_EVENT_RECEIVED:
            if(uart_reader_state != UART_READER_STATE_FULL)
            {
                rx_count = csi_uart_receive_query(handle,uart_reader_buf,sizeof(uart_reader_buf));
             //   printf("rx_count  %d\n",rx_count);
                if(rx_count>0)
                    uart_reader_read_frame(uart_reader_buf,rx_count);
            }
			break;
        default:
            break;
           
    }

读取数据后利用uart_reader_read_frame按照通信协议进行拼包,在拼包过程中一定要考虑全面,把各种边界条件考虑进去,这里我把独创源码进行分享了,如果感觉有用的话记得点赞评论哦~

static int uart_reader_read_frame(uint8_t * data,int rx_count)
{
    int i=0;
    
    while(i<rx_count)
    {
        if(uart_reader_state == UART_READER_STATE_INIT)
        {
            if(data[i]!=0x20)
            {
                i++;
                continue;
            }
            uart_reader_state = UART_READER_STATE_HEAD;
            uart_reader_len = 0;
            i++;
            uart_reader_off = 0;
            if((rx_count-i)<3)
            {
                if((rx_count-i)>0)
                {
  //                  printf("(rx_count-i):%diiiii\n",(rx_count-i));
                    memcpy(&uart_reader_frame[uart_reader_off],&data[i],(rx_count-i));
                    uart_reader_off += (rx_count-i);
                }
                return;
            }
                                    
            
        }else if(uart_reader_state == UART_READER_STATE_HEAD)
        {
  //          printf("uart_reader_off:%d\n",uart_reader_off);
            memcpy(&uart_reader_frame[uart_reader_off],&data[i],3-uart_reader_off);
            uart_reader_len = uart_reader_frame[2];
 //           printf("uart_reader_len:%d\n",uart_reader_len);
            uart_reader_len+=2;
            uart_reader_state = UART_READER_STATE_DATA;
            i+=(3-uart_reader_off);
            uart_reader_off=3;
            if((rx_count-i)<uart_reader_len)
            {
  //              printf("(rx_count-i):%d\n",(rx_count-i));
                if((rx_count-i)>0)
                {
  //                  printf("(rx_count-i):%dhhhh\n",(rx_count-i));
                    memcpy(&uart_reader_frame[uart_reader_off],&data[i],(rx_count-i));
                    uart_reader_off += (rx_count-i);
                }
                return ;
            }
            
  //          printf("begain rev data\n");
        }else if(uart_reader_state == UART_READER_STATE_DATA)
        {
            int j;
  //          printf("uart_reader_off:%d\n",uart_reader_off);
            memcpy(&uart_reader_frame[uart_reader_off],&data[i],uart_reader_len+3-uart_reader_off);
            i+=(uart_reader_len+3-uart_reader_off);
            uart_reader_off = 0;
            printf("receive:");
            for(j=0; j<uart_reader_len+3; j++)
            {
                printf("%2.2x",uart_reader_frame[j]);
            }
            printf("\n");
            j = krhino_sem_give(&uart_reader_sem);
            if (j != RHINO_SUCCESS) {
                return;
            }
            uart_reader_state = UART_READER_STATE_FULL;
        }else{
            printf("receive complete????????\r\n");
        }
    }

}

到这里一个完整的串口数据包以及从串口中获得,剩下的就可以提取想用的信息进行处理了。

牵扯到的小知识整理

在这里插入图片描述

在这里插入图片描述

小结

这个任务共做了4天,难度主要在于接口文档不全,以及ALIOS的资料较少,通过这个任务对自己的C语言提升很大,代码基本上都可以看懂了,特别是利用指针在程序中传递数据,指针在传递数据的时候可以这样理解,你向某个地址放东西,如果你知道这个地址,那么在哪个文件中都可以取这个数据,因为数据放的地址已经知道了,很灵活。就是把脑子的概念扭转过来,对习惯对地址操作的思维方式。接下来开始移植libpng,下篇文章再见!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值