210和HMI通信01

main.c

//IO18---IO23,普通IO口,输入状态,判断是不是0,是0,说明垃圾满
#include "sleep.h"
#include <stdio.h>
#include <unistd.h>
#include "kpu.h"
#include <platform.h>
#include <printf.h>
#include <string.h>
#include <stdlib.h>
#include "bsp.h"
#include <sysctl.h>
#include "plic.h"
#include "utils.h"
#include <float.h>
#include "uarths.h"
#include "fpioa.h"
#include "lcd.h"
#include "pin_config.h"
#include "dvp.h"
#include "ov2640.h"
#include "uarths.h"
#include "image_process.h"
#include "board_config.h"
#include "nt35310.h"
#include "gpiohs.h"
#include "gpio.h"
#include "spi.h"
#define INCBIN_STYLE INCBIN_STYLE_SNAKE
#define INCBIN_PREFIX
#include "incbin.h"
#include "image.h"
#include <string.h>
//cmake .. -DPROJ=keypad -G "MinGW Makefiles" 

#define xmmpul 2   //1000个脉冲,是1mm,测试可以修改

#define PLL0_OUTPUT_FREQ 1000000000UL
#define PLL1_OUTPUT_FREQ 400000000UL
#define PLL2_OUTPUT_FREQ 45158400UL

volatile uint8_t ircut_value = 0x01;
volatile uint8_t r_ircut_value = 0x00;

volatile uint32_t g_ai_done_flag;

volatile uint8_t g_dvp_finish_flag;
static image_t kpu_image, display_image, crop_image;

extern const unsigned char gImage_image[] __attribute__((aligned(128)));

static uint16_t lcd_gram[320 * 240] __attribute__((aligned(32)));
kpu_model_context_t task1;

INCBIN(model, "m.kmodel");//m.kmodel在src里面对应的要cmake的文件夹内
#define min(a,b) (((a) < (b)) ? (a) : (b))
static void ai_done(void* userdata)
{
    
    
    g_ai_done_flag = 1;
    
    float *features;
    size_t count;
    kpu_get_output(&task1, 0, (uint8_t **)&features, &count);
    count /= sizeof(float);

    size_t i;
    for (i = 0; i < count; i++)
    {
    
    
        if (i % 64 == 0)
            printf("\n");
        printf("%f, ", features[i]);
    }

    printf("\n");
}

static int dvp_irq(void *ctx)
{
    
    
    if (dvp_get_interrupt(DVP_STS_FRAME_FINISH))
    {
    
    
        dvp_config_interrupt(DVP_CFG_START_INT_ENABLE | DVP_CFG_FINISH_INT_ENABLE, 0);
        dvp_clear_interrupt(DVP_STS_FRAME_FINISH);
        g_dvp_finish_flag = 1;
    }
    else
    {
    
    
        dvp_start_convert();
        dvp_clear_interrupt(DVP_STS_FRAME_START);
    }
    return 0;
}


/**
* Function       hardware_init
* @author        Gengyue
* @date          2020.05.27
* @brief         硬件初始化,绑定GPIO口
* @param[in]     void
* @param[out]    void
* @retval        void
* @par History   无
*/
void hardware_init(void)
{
    
    
    fpioa_set_function(PIN_LED_0, FUNC_LED0);
    fpioa_set_function(PIN_LED_1, FUNC_LED1);

    fpioa_set_function(PIN_LJT_0, FUNC_LJT0);
    fpioa_set_function(PIN_LJT_1, FUNC_LJT1);
    fpioa_set_function(PIN_LJT_2, FUNC_LJT2);
    fpioa_set_function(PIN_LJT_3, FUNC_LJT3);
    fpioa_set_function(PIN_LJT_4, FUNC_LJT4);
    fpioa_set_function(PIN_LJT_5, FUNC_LJT5);

    fpioa_set_function(PIN_DIR_0, FUNC_DIR0);
    fpioa_set_function(PIN_PUL_0, FUNC_PUL0);
    fpioa_set_function(PIN_DIR_1, FUNC_DIR1);
    fpioa_set_function(PIN_PUL_1, FUNC_PUL1);

  /* Init DVP IO map and function settings */
    fpioa_set_function(OV_RST_PIN, FUNC_CMOS_RST);
    fpioa_set_function(OV_PWDN_PIN, FUNC_CMOS_PWDN);
    fpioa_set_function(OV_XCLK_PIN, FUNC_CMOS_XCLK);
    fpioa_set_function(OV_VSYNC_PIN, FUNC_CMOS_VSYNC);
    fpioa_set_function(OV_HREF_PIN, FUNC_CMOS_HREF);
    fpioa_set_function(OV_PCLK_PIN, FUNC_CMOS_PCLK);
    fpioa_set_function(OV_SCCB_SCLK_PIN, FUNC_SCCB_SCLK);
    fpioa_set_function(OV_SCCB_SDA_PIN, FUNC_SCCB_SDA);

    /* Init SPI IO map and function settings */
    fpioa_set_function(LCD_DC_PIN, FUNC_LCD_DC);
    fpioa_set_function(LCD_CS_PIN, FUNC_LCD_CS);
    fpioa_set_function(LCD_RW_PIN, FUNC_LCD_RW);
    fpioa_set_function(LCD_RST_PIN, FUNC_LCD_RST);

    sysctl_set_spi0_dvp_data(1);
      // fpioa映射
    fpioa_set_function(PIN_UART_USB_RX, FUNC_UART_USB_RX);
    fpioa_set_function(PIN_UART_USB_TX, FUNC_UART_USB_TX);

    fpioa_set_function(PIN_UART_HMI_RX, FUNC_UART_HMI_RX);
    fpioa_set_function(PIN_UART_HMI_TX, FUNC_UART_HMI_TX);

}static void io_set_power(void)
{
    
    
    /* Set dvp and spi pin to 1.8V */
    sysctl_set_power_mode(SYSCTL_POWER_BANK6, SYSCTL_POWER_V18);
    sysctl_set_power_mode(SYSCTL_POWER_BANK7, SYSCTL_POWER_V18);
}

void rgb888_to_lcd(uint8_t *src, uint16_t *dest, size_t width, size_t height)
{
    
    
    size_t i, chn_size = width * height;
    for (size_t i = 0; i < width * height; i++)
    {
    
    
        uint8_t r = src[i];
        uint8_t g = src[chn_size + i];
        uint8_t b = src[chn_size * 2 + i];

        uint16_t rgb = ((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (b >> 3);
        size_t d_i = i % 2 ? (i - 1) : (i + 1);
        dest[d_i] = rgb;
    }
}

void lcd_ram_draw_rgb888(uint8_t *src, uint16_t *dest, size_t width, size_t height, size_t x_off, size_t y_off, size_t stride)
{
    
    
    size_t x, y, chn_size = width * height;
    for (size_t y = 0; y < min(height, 240); y++)
    {
    
    
        for (size_t x = 0; x < width; x++)
        {
    
    
            size_t i = y * width + x;
            uint8_t r = src[i];
            uint8_t g = src[chn_size + i];
            uint8_t b = src[chn_size * 2 + i];

            uint16_t rgb = ((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (b >> 3);
            i = (y + y_off) * stride + x + x_off;
            size_t d_i = i % 2 ? (i - 1) : (i + 1);
            dest[d_i] = rgb;
        }
    }
}

int argmax(float* src, size_t count)
{
    
    
    float max = FLT_MIN;
    size_t i, max_i = 0;
    for (i = 0; i < count; i++)
    {
    
    
        if (src[i] > max)
        {
    
    
            max = src[i];
            max_i = i;
        }
    }

    return max_i;
}


//步进电机运动函数,因为电机的步距角不一样
void movestepper0(int seldir ,uint32_t mm0, int vms)  //1mm----pul个脉冲
{
    
    
    uint64_t i;
    //和51单片机不一样,这个是GPIO_PV_HIGH代表高电平
    gpio_pin_value_t valuetemp = GPIO_PV_HIGH;

    gpio_pin_value_t valuehigh = GPIO_PV_HIGH;
    gpio_pin_value_t valuelow = GPIO_PV_LOW;
    //判断方向
    if(seldir==1)
    {
    
    
        valuetemp = GPIO_PV_HIGH;
    } 
    else if(seldir==0)
    {
    
    
        valuetemp = GPIO_PV_LOW;
    }
    //设置方向
   //用的是高速IO端口模式,所以是gpiohs
    gpiohs_set_pin(StepDir0_GPIONUM, valuetemp);  
    //根据mm,计算脉冲数
    for(i=0;i<mm0*xmmpul;i++)
    {
    
    
        gpiohs_set_pin(StepPul0_GPIONUM, valuehigh);
        msleep(vms);//
    
        gpiohs_set_pin(StepPul0_GPIONUM, valuelow);
        msleep(vms);//

    }

}
//*************************************************************************************
void UART_SendHMI_Byte(char mydata)	// 发送一个字节
{
    
    
    uart_send_data(UART_HMI_NUM, &mydata, 1);
}
//*************************************************************************************
void UART_SendHMI_Str(char *s)	  //发送文本串
{
    
    
 int i=0;
 while(s[i]!=0)
 {
    
    
 	UART_SendHMI_Byte(s[i]);
 	i++;
 }
}
//*************************************************************************************
void UART_SendHMI_END(void)   //发送结束符
{
    
    
	 UART_SendHMI_Byte(0xFF);
	 UART_SendHMI_Byte(0xFF);
	 UART_SendHMI_Byte(0xFF);
}
//*************************************************************************************
/**
* Function       main
* @author        Gengyue
* @date          2020.05.27
* @brief         主函数,程序的入口
* @param[in]     void
* @param[out]    void
* @retval        0
* @par History   无
*/
int main(void)
{
    
    
    int i=0;
    hardware_init();// 硬件引脚初始化
           /* Set CPU and dvp clk */
    sysctl_pll_set_freq(SYSCTL_PLL0, 800000000UL);
    sysctl_pll_set_freq(SYSCTL_PLL1, 400000000UL);
    sysctl_pll_set_freq(SYSCTL_PLL2, 45158400UL);
    sysctl_clock_enable(SYSCTL_CLOCK_AI);
    plic_init();
    io_set_power();

    gpio_init();    // 使能GPIO的时钟
    // 设置LED0和LED1的GPIO模式为输出
    gpio_set_drive_mode(LED0_GPIONUM, GPIO_DM_OUTPUT);
    gpio_set_drive_mode(LED1_GPIONUM, GPIO_DM_OUTPUT);  
    // 先关闭LED0和LED1
    gpio_pin_value_t value = GPIO_PV_HIGH;
    gpio_set_pin(LED0_GPIONUM, value);
    gpio_set_pin(LED1_GPIONUM, value);
    // 设置垃圾桶的传感器的GPIO模式为上拉输入
    gpiohs_set_drive_mode(LJT0_GPIONUM, GPIO_DM_INPUT_PULL_UP);
    gpiohs_set_drive_mode(LJT1_GPIONUM, GPIO_DM_INPUT_PULL_UP);
    gpiohs_set_drive_mode(LJT2_GPIONUM, GPIO_DM_INPUT_PULL_UP);
    gpiohs_set_drive_mode(LJT3_GPIONUM, GPIO_DM_INPUT_PULL_UP);
    gpiohs_set_drive_mode(LJT4_GPIONUM, GPIO_DM_INPUT_PULL_UP);
    gpiohs_set_drive_mode(LJT5_GPIONUM, GPIO_DM_INPUT_PULL_UP);
    //设置步进电机的方向和脉冲引脚是输出模式
    gpiohs_set_drive_mode(StepDir0_GPIONUM, GPIO_DM_OUTPUT);
    gpiohs_set_drive_mode(StepPul0_GPIONUM, GPIO_DM_OUTPUT);
    gpiohs_set_drive_mode(StepDir1_GPIONUM, GPIO_DM_OUTPUT);
    gpiohs_set_drive_mode(StepPul1_GPIONUM, GPIO_DM_OUTPUT);

    uart_init(UART_USB_NUM);
    uart_configure(UART_USB_NUM, 115200, UART_BITWIDTH_8BIT, UART_STOP_1, UART_PARITY_NONE);

    uart_init(UART_HMI_NUM);
    uart_configure(UART_HMI_NUM, 9600, UART_BITWIDTH_8BIT, UART_STOP_1, UART_PARITY_NONE);
    /* 开机发送hello yahboom! */
    char *hello = {
    
    "hello yahboom!\n"};
    uart_send_data(UART_USB_NUM, hello, strlen(hello));


      /* LCD init */
    printf("LCD init\n");
    lcd_init();
    lcd_set_direction(DIR_YX_LRUD);
    lcd_clear(BLACK);
    
  //  lcd_draw_picture_half(0, 0, 320, 240, logo);
    lcd_draw_string(70, 40, "Hello uuyyttr!", RED);
    lcd_draw_string(70, 60, "c", BLUE);
    //lcd_draw_char(70,80,'o',RED);//lcd_draw_char(x, y, *str, color);
    sleep(1);

    /* DVP init */
    printf("DVP init\n");
    dvp_init(8);
    dvp_set_xclk_rate(24000000);
    dvp_enable_burst();
    dvp_set_output_enable(0, 1);
    dvp_set_output_enable(1, 1);
    dvp_set_image_format(DVP_CFG_RGB_FORMAT);
    dvp_set_image_size(320, 240);
    ov2640_init();

    kpu_image.pixel = 3;
    kpu_image.width = 320;
    kpu_image.height = 240;
    image_init(&kpu_image);
    
    display_image.pixel = 2; //2->3 LIUSEN
    display_image.width = 320;
    display_image.height = 240;
    image_init(&display_image);
    
    crop_image.pixel = 3;
    crop_image.width = 224;
    crop_image.height = 224;
    image_init(&crop_image);

    //存放AI图像的地址,供AI模块进行算法处理(红色、绿色、蓝色/分量地址)
    dvp_set_ai_addr((uint32_t)kpu_image.addr, (uint32_t)(kpu_image.addr + 320 * 240), (uint32_t)(kpu_image.addr + 320 * 240 * 2));
    //设置采集图像在内存中的存放地址,可以用来显示
    dvp_set_display_addr((uint32_t)display_image.addr);
    //图像开始采集中断| 图像结束采集中断
    dvp_config_interrupt(DVP_CFG_START_INT_ENABLE | DVP_CFG_FINISH_INT_ENABLE, 0);
    //禁用自动接收图像模式
    dvp_disable_auto();

    /* DVP interrupt config */
    printf("DVP interrupt config\n");
    plic_set_priority(IRQN_DVP_INTERRUPT, 1);               //设置中断优先级
    plic_irq_register(IRQN_DVP_INTERRUPT, dvp_irq, NULL);   //注册外部中断函数
    plic_irq_enable(IRQN_DVP_INTERRUPT);                    //使能外部中断
   char recv = 0;
   unsigned char HMICmd[50]="pic";
  // lcd_draw_char(10,0,'g',RED);
    while (1)
    {
    
    
       //查询几个GPIO垃圾桶,返回传感器..参考keypad的案例代码
       gpio_pin_value_t state_LJT0 =  gpiohs_get_pin(LJT0_GPIONUM);
       gpio_pin_value_t state_LJT1 =  gpiohs_get_pin(LJT1_GPIONUM);
       gpio_pin_value_t state_LJT2 =  gpiohs_get_pin(LJT2_GPIONUM);
       gpio_pin_value_t state_LJT3 =  gpiohs_get_pin(LJT3_GPIONUM);
       gpio_pin_value_t state_LJT4 =  gpiohs_get_pin(LJT4_GPIONUM);
       gpio_pin_value_t state_LJT5 =  gpiohs_get_pin(LJT5_GPIONUM);
       //gpio_pin_value_t value = GPIO_PV_HIGH; GPIO_PV_LOW
       //LED 低电平亮,高电平不亮
       if(!state_LJT0)
              {
    
    
              //    gpio_set_pin(LED0_GPIONUM, GPIO_PV_LOW);
                  gpio_set_pin(LED1_GPIONUM, GPIO_PV_LOW);
              }
        if(!state_LJT1)
              {
    
    
                //  gpio_set_pin(LED0_GPIONUM, GPIO_PV_LOW);
                  gpio_set_pin(LED1_GPIONUM, GPIO_PV_HIGH);
              }
        if(!state_LJT2)
              {
    
    
                  //gpio_set_pin(LED0_GPIONUM, GPIO_PV_HIGH);
                  gpio_set_pin(LED1_GPIONUM, GPIO_PV_LOW);
              }
        if(!state_LJT3)
              {
    
    
                 // gpio_set_pin(LED0_GPIONUM, GPIO_PV_HIGH);
                  gpio_set_pin(LED1_GPIONUM, GPIO_PV_HIGH);
              }

    //      //步进电机测试,正方向,两个电机都走100000个脉冲
    //     gpiohs_set_pin(StepDir0_GPIONUM, GPIO_PV_HIGH);  
    //     gpiohs_set_pin(StepDir1_GPIONUM, GPIO_PV_HIGH);
    //     for(i=0;i<100000;i++)
    //    {
    
    
    //     gpiohs_set_pin(StepPul0_GPIONUM, GPIO_PV_HIGH);    
    //     gpiohs_set_pin(StepPul1_GPIONUM, GPIO_PV_HIGH);
    //     msleep(1);//5000
    //     gpiohs_set_pin(StepPul0_GPIONUM, GPIO_PV_LOW); 
    //     gpiohs_set_pin(StepPul1_GPIONUM, GPIO_PV_LOW);
    //     msleep(1);//5000
    //    }
    //    sleep(10);  
    //      //步进电机测试,反方向,两个电机都走100000个脉冲
    //     gpiohs_set_pin(StepDir0_GPIONUM, GPIO_PV_LOW);
    //     gpiohs_set_pin(StepDir1_GPIONUM, GPIO_PV_LOW);
    //     //步进电机测试,正方向,两个电机都走100000个脉冲
    //     for(i=0;i<100000;i++)
    //    {
    
    
    //     gpiohs_set_pin(StepPul0_GPIONUM, GPIO_PV_HIGH);    
    //     gpiohs_set_pin(StepPul1_GPIONUM, GPIO_PV_HIGH);
    //     msleep(1);//5000
    //     gpiohs_set_pin(StepPul0_GPIONUM, GPIO_PV_LOW);
    //     gpiohs_set_pin(StepPul1_GPIONUM, GPIO_PV_LOW);
    //     msleep(1);//5000
    //    }

    //     sleep(10);  
    //     movestepper0(0,100,1);  //0方向,100个mm,速度是1ms
    //     sleep(10);
    //     movestepper0(1,100,1);  //0方向,100个mm,速度是1ms
    //     sleep(10);  

        // g_dvp_finish_flag = 0;
        // dvp_clear_interrupt(DVP_STS_FRAME_START | DVP_STS_FRAME_FINISH);
        // dvp_config_interrupt(DVP_CFG_START_INT_ENABLE | DVP_CFG_FINISH_INT_ENABLE, 1);
        // while (g_dvp_finish_flag == 0)
        //     ;
            
        // image_crop(&kpu_image, &crop_image, 48, 8);

        // g_ai_done_flag = 0;
        printf("A\n");
        /* 等待串口信息,并通过串口发送出去 */
        if(uart_receive_data(UART_USB_NUM, &recv, 1))
        {
    
    
            uart_send_data(UART_USB_NUM, &recv, 1);
        }
        printf("B\n");
           /* 等待串口信息,并通过串口发送出去 */
           while(1)
           {
    
    
                state_LJT0 =  gpiohs_get_pin(LJT0_GPIONUM);
                state_LJT1 =  gpiohs_get_pin(LJT1_GPIONUM);
                if(!state_LJT0)   //IO18
                {
    
    
                   // UART_SendHMI_Str(char *s);
                    UART_SendHMI_Str("C.b8.bco=63488");	 //变红色
                    UART_SendHMI_END();
                    gpio_set_pin(LED1_GPIONUM, GPIO_PV_LOW);

                }
                  if(!state_LJT1)   //IO18
                {
    
    
                   // UART_SendHMI_Str(char *s);
                    UART_SendHMI_Str("C.b8.bco=2014");	 //变红色
                    UART_SendHMI_END();
                    gpio_set_pin(LED1_GPIONUM, GPIO_PV_LOW);

                }
                 if(uart_receive_data(UART_HMI_NUM, &recv, 1))//串口接收,应该放在中断
                {
    
    
                        printf("C\n");
                        lcd_clear(BLACK);
                        lcd_draw_char(70,80,recv+0x30,BLUE);
                        printf("D\n");       
                }


           }
       

    }
    return 0;
}

pin_config.h

/**
* @par  Copyright (C): 2016-2022, Shenzhen Yahboom Tech
* @file         pin_config.c
* @author       Gengyue
* @version      V1.0
* @date         2020.05.27
* @brief        硬件引脚与软件GPIO的宏定义
* @details      
* @par History  见如下说明
*                 
* version:	由于K210使用fpioa现场可编程IO阵列,允许用户将255个内部功能映射到芯片外围的48个自由IO上
*           所以把硬件IO和软件GPIO功能抽出来单独设置,这样更容易理解。
*/
#ifndef _PIN_CONFIG_H_
#define _PIN_CONFIG_H_
/*****************************HEAR-FILE************************************/
#include "fpioa.h"
#include "uart.h"

/*****************************HARDWARE-PIN*********************************/
// 硬件IO口,与原理图对应
#define PIN_LED_0             (0)   //LED灯
#define PIN_LED_1             (17)

#define PIN_LJT_0             (18)  //垃圾桶LJT
#define PIN_LJT_1             (19)
#define PIN_LJT_2             (20)
#define PIN_LJT_3             (21)
#define PIN_LJT_4             (22)
#define PIN_LJT_5             (23)

#define PIN_DIR_0             (1)  //传送步进电机0方向  IO12是普通IO
#define PIN_PUL_0             (2)   //传送步进电机0脉冲输出  普通IO
#define PIN_DIR_1             (3)   //传送步进电机1方向   
#define PIN_PUL_1             (16)   //传送步进电机1脉冲输出

#define PIN_UART_USB_RX       (4)
#define PIN_UART_USB_TX       (5)

#define PIN_UART_HMI_RX       (13)
#define PIN_UART_HMI_TX       (14)

/*****************************SOFTWARE-GPIO********************************/
// 软件GPIO口,与程序对应
#define LED0_GPIONUM          (0)
#define LED1_GPIONUM          (1)

#define LJT0_GPIONUM          (2)
#define LJT1_GPIONUM          (3)
#define LJT2_GPIONUM          (4)
#define LJT3_GPIONUM          (5)
#define LJT4_GPIONUM          (6)
#define LJT5_GPIONUM          (7)

#define StepDir0_GPIONUM       (8)
#define StepPul0_GPIONUM       (9)
#define StepDir1_GPIONUM       (10)
#define StepPul1_GPIONUM       (11)

#define UART_USB_NUM           UART_DEVICE_3
#define UART_HMI_NUM           UART_DEVICE_1
/*****************************FUNC-GPIO************************************/
// GPIO口的功能,绑定到硬件IO口
#define FUNC_LED0             (FUNC_GPIO0 + LED0_GPIONUM)
#define FUNC_LED1             (FUNC_GPIO0 + LED1_GPIONUM)
//IO口18--23对应HS高速口,看芯片手册的引脚定义表
#define FUNC_LJT0             (FUNC_GPIOHS0 + LJT0_GPIONUM)
#define FUNC_LJT1             (FUNC_GPIOHS0 + LJT1_GPIONUM)
#define FUNC_LJT2             (FUNC_GPIOHS0 + LJT2_GPIONUM)
#define FUNC_LJT3             (FUNC_GPIOHS0 + LJT3_GPIONUM)
#define FUNC_LJT4             (FUNC_GPIOHS0 + LJT4_GPIONUM)
#define FUNC_LJT5             (FUNC_GPIOHS0 + LJT5_GPIONUM)

#define FUNC_DIR0             (FUNC_GPIOHS0 + StepDir0_GPIONUM)
#define FUNC_PUL0             (FUNC_GPIOHS0 + StepPul0_GPIONUM)
#define FUNC_DIR1             (FUNC_GPIOHS0 + StepDir1_GPIONUM)
#define FUNC_PUL1             (FUNC_GPIOHS0 + StepPul1_GPIONUM)

#define FUNC_UART_USB_RX       (FUNC_UART1_RX + UART_USB_NUM * 2)
#define FUNC_UART_USB_TX       (FUNC_UART1_TX + UART_USB_NUM * 2)

#define FUNC_UART_HMI_RX       (FUNC_UART1_RX + UART_HMI_NUM * 2)
#define FUNC_UART_HMI_TX       (FUNC_UART1_TX + UART_HMI_NUM * 2)
#endif /* _PIN_CONFIG_H_ */

猜你喜欢

转载自blog.csdn.net/lmf666/article/details/111278145
今日推荐