I wish to take the samples from pic16f877a,4Mhz HS( if it is given a sine wave input) and plot the same.I am giving 230vp sine wave 50hz as input and transformed it into 5v range and level shifted it into positive voltages.
This is my code
// Loop variable
float val,val1;//Declare the adcvalue stored variables
char uart_rd[50],uart_rd1[50];
void rmsv();
void adc_uart();//adc read and uart write
void interrupt(){
if (PIR1.ADIF) {
PIR1.ADIF=0; // clear AD interrupt flag
val= (ADRESH << 8) | ADRESL; // read dadta from channel 0
{
val1=(val*325.0)/1023.0;
FloatToStr(val1,uart_rd1);
strncpy(uart_rd,uart_rd1,3);
UART1_Write_Text(uart_rd1);
//UART1_Write(10);
UART1_Write(13);
delay_us(1);
}
Delay_Cyc(3); //wait acquisition time
ADCON0.F2=1; //start conversion again
}
}
void main()
{
TRISA=0XFF;//porta as input
ADCON1 = 0x82; // AN0->AN4 selected as analog input
ADCON0 = 0b11000001; // Configue analog mode
INTCON.GIE = 1; //Enable global interrupt
INTCON.PEIE = 1; //Enable peripheral interrupt
PIE1.ADIE = 1; //Enable ADC interrupt
Delay_us(20); //wait for acquisition time
ADCON0.F2 = 1; //start conversion
// ADCON1=0X81;
UART1_Init(9600); // Initialize UART module at 9600 bps
//ADC_Init();
while(1);
}
I have checked the values in hyperterminal and see that the controller not even sample the peak voltage.I wish to have the samples correctly so that I can able to plot the waveform correctly
Probably it is not a software problem. You say "controller not even sample the peak voltage" and that the signal rage is between 5V and 0V. Well, if you have configured your PIC ADC using the PIC power voltage (Vp) as reference voltage and if the power voltage is less than 5V ( Vp<5V), then your max adc Voltage range is Vp. It could cause that the peak of the sin signal after ADC acquisition looks cut.
Vp ________ _________ _________
\ / \ /
\ / \ /
\ / \ /
\ / \ /
0 \_/ \_/
Measure the power voltage on the PIC pin and if it is the reason then adjust the voltage source or transform the signal into Vp range .
Related
Im trying to construct an AD-converter from a potentiometer to an Arduino. I´m trying to learn MCC in MPLAB at the same time. So far I have generated a code that fits my PIC (I think...). My problem is now that my bit represented output is incorrect. This is hoe my PIC16F1827 is configured (se picture)
RA0 = input, RB1 and RB2 = EUSART and RB0,RB3,RA7,RA6,RB7,RB6,RB5,RB4 = output.
My main file look like this (se code). I get an output but its represented wrong and i can´t figure ut why...
char ADC_temp_in;
while (1) //Infinite Loop
{
// Add your application code
printf("pot_value =%d\r\n", ADC_GetConversion(channel_AN0_ADC));
ADC_temp_in = ADC_GetConversion(channel_AN0_ADC); // temp
PORTB = ADC_temp_in; //Write Lower bits to PORTB
PORTA = ADC_temp_in>>6; //Write Higher 2 bits to PORTA
__delay_ms(100); //Delay
}
VREF+ = 5V and is connected directly to VDD.
My goal is to have RB0 as LSB and RA7 as MSB with the voltage difference 0-5 V with the potentiometer.
Two things:
ADC_temp_in had to by a 16 Bit value to hold a value greater than 8 Bit.
So try: uint16_t ADC_temp_in;
Of course your function ADC_GetConversion had to return a uint_16 value.
Another thing is, to get the MSB you had to shift your value 8 times right.
PORTA = ADC_temp_in>>8;
I need to control 4 individual LEDs via PWM on an ATTiny85. I have found lots of info on how to control 3 LEDs. But apparently to control 4 with PWM, you have to really twist the 85 into knots. Is there an easier way to handle 4 LEDs on the 85, or would it be better to step over to the 84? If I went with the 84, would I be likely to run into the same brick walls as with the 85?
I found this code for controlling 4 on the 85, but it's above my skill level. Anyone see any issues with it?
/* Four PWM Outputs */
// ATtiny85 outputs
const int Red = 0;
const int Green = 1;
const int Blue = 4;
const int White = 3;
volatile uint8_t* Port[] = {&OCR0A, &OCR0B, &OCR1A, &OCR1B};
void setup() {
pinMode(Red, OUTPUT);
pinMode(Green, OUTPUT);
pinMode(Blue, OUTPUT);
pinMode(White, OUTPUT);
// Configure counter/timer0 for fast PWM on PB0 and PB1
TCCR0A = 3<<COM0A0 | 3<<COM0B0 | 3<<WGM00;
TCCR0B = 0<<WGM02 | 3<<CS00; // Optional; already set
// Configure counter/timer1 for fast PWM on PB4
TCCR1 = 1<<CTC1 | 1<<PWM1A | 3<<COM1A0 | 7<<CS10;
GTCCR = 1<<PWM1B | 3<<COM1B0;
// Interrupts on OC1A match and overflow
TIMSK = TIMSK | 1<<OCIE1A | 1<<TOIE1;
}
ISR(TIMER1_COMPA_vect) {
if (!bitRead(TIFR,TOV1)) bitSet(PORTB, White);
}
ISR(TIMER1_OVF_vect) {
bitClear(PORTB, White);
}
// Sets colour Red=0 Green=1 Blue=2 White=3
// to specified intensity 0 (off) to 255 (max)
void SetColour (int colour, int intensity) {
*Port[colour] = 255 - intensity;
}
void loop() {
for (int i=-255; i <= 254; i++) {
OCR0A = abs(i);
OCR0B = 255-abs(i);
OCR1A = abs(i);
OCR1B = 255-abs(i);
delay(10);
}
}
If you want to save pins at the expense of a more complicated strategy, you can get away with only 3 pins by connecting the LEDs as two sets of two like this...
Instead of using the built in PWM, you will need to do the PWM manually by setting a timer and then changing the INPUT/OUTPUT and ON/OFF of each of the pins each time the timer expires.
+-----+----------+----------+----------+
| LED | A | B | C |
+-----+----------+----------+----------+
| 1 | OUTPUT 1 | INPUT | OUTPUT 0 |
| 2 | OUTPUT 0 | INPUT | OUTPUT 1 |
| 3 | INPUT | OUTPUT 1 | OUTPUT 0 |
| 4 | INPUT | OUTPUT 0 | OUTPUT 1 |
+-----+----------+----------+----------+
Update or comment if you want more details on this strategy.
An easy strategy is to multiplex the 4 LEDs onto a single PWM pin. This will let independently control the brightness of each LED on the ATTINY using 5 pins total.
So, for example, you could connect all 4 of the cathodes together and connect those to a single PWM pin. Then you connect each of the 4 anodes to a different IO pin.
At any given moment, only one of the anodes is in output mode - the others are left floating. The means that at most 1 single LED is active and its brightness is controlled by the PWM duty cycle.
You can then use the overflow ISR for the PWM timer to activate the next LED in the sequence after each PWM cycle. You also update the PWM match to reflect the brightness of the next LED.
If you rotate though the LEDs quickly (faster than, say, 60 times per second), then visually they all just look like they are on at the desired brightness. PWM, after all, is just blinking an LED too quickly to see, so we are just adding a second dimension on to it.
One downside: Since only a single LED is on at any moment, the maximum total brightness will theoretically be 1/4 of what it would be if you drove all the LEDs independently. In practice this is likely an issue since the ATTINY is limited to how much current it can pass though all if its pins at once if you tried to light all the LEDs at the same time.
One hint: when setting up the PWM timer, make is so that the LED is OFF at the beginning of the cycle and turns on in the middle. This will give the ISR time to step to the next LED while all LEDs are off. This is better becuase it is Easy to see an LED that is on when it should not be, but not so easy to see an LED that is off when it should be on.
One suggestion: I will get flamed for this, but you can leave out any current limiting resistors when doing this since each LED is only on for at most 1/4 of the time. This will give you more brightness and also make it so you can dial down the PWM duty cycle so you have more off time at the beginning of each cycle to step to the next LED.
I have used this technique successfully many times, and even have been able to multiplex 6 RGB LEDs (three channels each) onto one chip and it works great.
Update the question if you have any questions about the details!
I'm trying to read byte per byte from the RX FIFO, that's 8 bytes deep.
The problem is that when the first byte is received, I have to wait for 8 other bytes to finally get the first byte on U1RXREG.
I'd like to know how to perform some dummy reads on the FIFO to access a particuar byte and "flush" it. Simply putting U1RXREG in an array doesn't do the trick.
Here's my initialization :
void UART_Initialize(void)
{
// SIDL: Stop in Idle Mode bit : 1 = Discontinue module operation when the device enters Idle mode
U1MODEbits.SIDL = 0;
// IREN: IrDA Encoder and Decoder Enable bit : 0 = IrDA is disabled
U1MODEbits.IREN = 0;
// RTSMD: Mode Selection for UxRTS Pin bit : 0 = UxRTS pin is in Flow Control mode
U1MODEbits.RTSMD = 0;
// UEN<1:0>: UARTx Enable bits : 10 = UxTX, UxRX, UxCTS and UxRTS pins are enabled and used
U1MODEbits.UEN1 = 1;
U1MODEbits.UEN0 = 0;
// WAKE: Enable Wake-up on Start bit Detect During Sleep Mode bit : 0 = Wake-up disabled
U1MODEbits.WAKE = 0;
// LPBACK: UARTx Loopback Mode Select bit : 0 = Loopback mode is disabled
U1MODEbits.LPBACK = 0;
// ABAUD: Auto-Baud Enable bit : 0 = Baud rate measurement disabled or completed
U1MODEbits.ABAUD = 0;
// RXINV: Receive Polarity Inversion bit : 0 = UxRX Idle state is ‘1’
U1MODEbits.RXINV = 0;
// BRGH: High Baud Rate Enable bit : 0 = Standard Speed mode – 16x baud clock enabled
U1MODEbits.BRGH = 0;
// PDSEL<1:0>: Parity and Data Selection bits : 01 = 8-bit data, even parity
U1MODEbits.PDSEL1 = 0;
U1MODEbits.PDSEL0 = 1;
// STSEL: Stop Selection bit : 0 = 1 Stop bit
U1MODEbits.STSEL = 0;
// ADM_EN: Automatic Address Detect Mode Enable bit : 0 = Automatic Address Detect mode is disabled
U1STAbits.ADM_EN = 0;
// UTXISEL<1:0>: TX Interrupt Mode Selection bits : 00 = Interrupt is generated and asserted while the transmit buffer contains at least one empty space
U1STAbits.UTXISEL1 = 0;
U1STAbits.UTXISEL0 = 0;
// UTXINV: Transmit Polarity Inversion bit : 0 = UxTX Idle state is ‘1’ (with IrDA disbled)
U1STAbits.UTXINV = 0;
// URXEN: Receiver Enable bit : 1 = UARTx receiver is enabled. UxRX pin is controlled by UARTx (if ON = 1)
U1STAbits.URXEN = 1;
// UTXBRK: Transmit Break bit : 0 = Break transmission is disabled or completed
U1STAbits.UTXBRK = 0;
// URXISEL<1:0>: Receive Interrupt Mode Selection bit : 00 = Interrupt flag bit is asserted while receive buffer is not empty (i.e., has at least 1 data character)
U1STAbits.URXISEL1 = 0;
U1STAbits.URXISEL0 = 0;
// ADDEN: Address Character Detect bit (bit 8 of received data = 1) : 0 = Address Detect mode is disabled
U1STAbits.ADDEN = 0;
// Baud Rate Calculation :
// FPB = 10MHz ; Desired Baud Rate = 9600 bauds
// => U1BRG = FPB/(16*BaudRate)-1 = 64 (error = 0,16%)
U1BRG = 64;
// Enable UART RX interrupts
//IEC1bits.U1RXIE = 1;
// Enable UART
// ON: UARTx Enable bit : 1 = UARTx is enabled. UARTx pins are controlled by UARTx as defined by the UEN<1:0> and UTXEN control bits.
U1MODEbits.ON = 1;
// UTXEN: Transmit Enable bit : 1 = UARTx transmitter is enabled. UxTX pin is controlled by UARTx (if ON = 1).
U1STAbits.UTXEN = 1;
}
For the moment I tried reading like this, in the while(1) loop, without success :
while (1)
{
uint8_t rxbyte[8];
bool b;
//if (U1STAbits.URXDA == 1)
while(!U1STAbits.URXDA);
rxbyte[0] = U1RXREG;
rxbyte[1] = U1RXREG;
rxbyte[2] = U1RXREG;
rxbyte[3] = U1RXREG;
rxbyte[4] = U1RXREG;
rxbyte[5] = U1RXREG;
rxbyte[6] = U1RXREG;
rxbyte[7] = U1RXREG;
sprintf(s, "I received : %u %u %u %u %u %u %u %u\n\r", rxbyte[0], rxbyte[1], rxbyte[2], rxbyte[3], rxbyte[4], rxbyte[5], rxbyte[6], rxbyte[7]);
myPrint(s);
IFS1bits.U1RXIF = 0;
}
The 8 bytes in rxbytes[] are always the same. I tried to clear the RX interrupt flag between the reads, reading URXDA also between the reads, add a delay, still no success, I still have to wait for 8 incoming bytes to access the first one.
Thanx in advance for your help !
Best regards.
Eric
I finally found the solution : I had a double configuration, one by MCC and one by myself, and it seems that having the interruptions activated caused this. Now I switched the interrupts off and I simply poll URXDA, and everything works fine.
Sorry for bothering you guys !
You can use your original method too. The problem with your While(1) loop is that you check if there is "at least 1 byte in the hardware Rx buffer" ( U1STAbits.URXDA tells you as soon as 1 byte is availlable ). When 1 byte is availlable, then you read 8 bytes inside the loop... so of course you will get 8 identical bytes when there is only 1 byte in the buffer.
On the internet there are quite a number of tutorials of how to control a shift register with a microcontroller, but is it actually possible to implement the shift register function with only the microcontroller?
If you have enough pins, I don't see why the naive way wouldn't work...
For an n-bit shift in register, you need n+2 pins:
One clock-in
One data-in
n data-out
The pseudocode of the implementation is:
var byte r := 0 // Assuming n=8, so 8 bits fit into a single byte
var byte i := 0
forever:
wait for clock-in = low
wait for clock-in = high
r := r << 0 | data-in
i := i + 1
if i = n:
data-out<1..n> := r
i = 0
If you want to make sure that data-out is updated synchronously, make sure you use pins of a single port: then the data-out<1..n> := r statement can literally be a single port register assignment.
If you want to run this concurrently with other code, you should be able to use a pin for clock-in that can trigger an interrupt.
I want to perform Multistage Constant Current Battery Charging in Modelica.
Could anyone help me? Thanks in advance.
model BatteryCharge
constant Real Voltage0 = 3;
parameter Real Current_vec[5] = {0.01,0.005,0.004,0.003,0.002};
Real Voltage;
Real Current;
// Integer k;
// algorithm
// k := 1;
// Current := Current_vec[k];
// Voltage := Voltage0 + Current * time;
//
// if Voltage > 4 then
// k := k+1;
// end if;
algorithm
for k in 1:5 loop
Current := Current_vec[k];
Voltage := Voltage0 + Current * time;
if Voltage > 4 then
break;
end if;
end for;
end BatteryCharge
I do really need help.
Pls do not ask me to do this in matlab since this is only one simple case of a part of my programming code.
It looks like you are mixing units of current, voltage and time. So, it is not very clear what you are trying to accomplish.
However, if you are trying to just generate voltage as a function of time, you could just use a Modelica.Blocks.Sources.TimeTable to give you voltage.